From 4d199cc868ab11d944304c29c64d06251624c7f2 Mon Sep 17 00:00:00 2001 From: dongyuanjushi Date: Mon, 7 Oct 2024 11:35:55 -0400 Subject: [PATCH 01/41] refactor agent query message --- aios/llm_core/llm_classes/base_llm.py | 7 +- aios/llm_core/llm_classes/bed_rock.py | 14 +-- aios/llm_core/llm_classes/claude_llm.py | 67 +++++++----- aios/llm_core/llm_classes/constant.py | 0 aios/llm_core/llm_classes/gemini_llm.py | 57 +++++----- aios/llm_core/llm_classes/gpt_llm.py | 109 +++++++++----------- aios/llm_core/llm_classes/groq_llm.py | 66 ++++++------ aios/llm_core/llm_classes/hf_native_llm.py | 42 ++++---- aios/llm_core/llm_classes/model_registry.py | 0 aios/llm_core/llm_classes/ollama_llm.py | 28 ++--- aios/llm_core/llm_classes/vllm.py | 24 ++--- aios/llm_core/llms.py | 7 +- aios/scheduler/fifo_scheduler.py | 47 ++++++--- pyopenagi/utils/chat_template.py | 4 +- 14 files changed, 246 insertions(+), 226 deletions(-) mode change 100755 => 100644 aios/llm_core/llm_classes/base_llm.py mode change 100755 => 100644 aios/llm_core/llm_classes/bed_rock.py mode change 100755 => 100644 aios/llm_core/llm_classes/constant.py mode change 100755 => 100644 aios/llm_core/llm_classes/gemini_llm.py mode change 100755 => 100644 aios/llm_core/llm_classes/gpt_llm.py mode change 100755 => 100644 aios/llm_core/llm_classes/hf_native_llm.py mode change 100755 => 100644 aios/llm_core/llm_classes/model_registry.py mode change 100755 => 100644 aios/llm_core/llm_classes/ollama_llm.py mode change 100755 => 100644 aios/llm_core/llm_classes/vllm.py diff --git a/aios/llm_core/llm_classes/base_llm.py b/aios/llm_core/llm_classes/base_llm.py old mode 100755 new mode 100644 index 7c5b85e76..b77fa90f6 --- a/aios/llm_core/llm_classes/base_llm.py +++ b/aios/llm_core/llm_classes/base_llm.py @@ -127,14 +127,13 @@ def parse_tool_calls(self, message): return tool_calls def address_request(self, - agent_process, + agent_request, temperature=0.0 ): - self.process(agent_process) - return + return self.process(agent_request) @abstractmethod def process(self, - agent_process, + agent_request, temperature=0.0) -> None: raise NotImplementedError diff --git a/aios/llm_core/llm_classes/bed_rock.py b/aios/llm_core/llm_classes/bed_rock.py old mode 100755 new mode 100644 index 34edd6331..e3247e642 --- a/aios/llm_core/llm_classes/bed_rock.py +++ b/aios/llm_core/llm_classes/bed_rock.py @@ -34,7 +34,7 @@ def load_llm_and_tokenizer(self) -> None: return def process(self, - agent_process, + agent_request, temperature=0.0) -> None: # ensure its the right model assert self.model_name.startswith("bedrock") and \ @@ -42,9 +42,9 @@ def process(self, """ simple wrapper around langchain functions """ - agent_process.set_status("executing") - agent_process.set_start_time(time.time()) - prompt = agent_process.message.prompt + agent_request.set_status("executing") + agent_request.set_start_time(time.time()) + prompt = agent_request.message.prompt from langchain_core.prompts import ChatPromptTemplate chat_template = ChatPromptTemplate.from_messages([ ("user", f"{prompt}") @@ -53,13 +53,13 @@ def process(self, self.model.model_kwargs['temperature'] = temperature try: response = self.model(messages) - agent_process.set_response( + agent_request.set_response( Response( response_message=response.content ) ) except IndexError: raise IndexError(f"{self.model_name} can not generate a valid result, please try again") - agent_process.set_status("done") - agent_process.set_end_time(time.time()) + agent_request.set_status("done") + agent_request.set_end_time(time.time()) return diff --git a/aios/llm_core/llm_classes/claude_llm.py b/aios/llm_core/llm_classes/claude_llm.py index 1105bf861..08e3121cd 100644 --- a/aios/llm_core/llm_classes/claude_llm.py +++ b/aios/llm_core/llm_classes/claude_llm.py @@ -46,12 +46,12 @@ def load_llm_and_tokenizer(self) -> None: self.model = anthropic.Anthropic() self.tokenizer = None - def process(self, agent_process: Any, temperature: float = 0.0) -> None: + def process(self, agent_request: Any, temperature: float = 0.0) -> None: """ Process a query using the Claude model. Args: - agent_process (Any): The agent process containing the query and tools. + agent_request (Any): The agent process containing the query and tools. temperature (float, optional): Sampling temperature for generation. Raises: @@ -60,13 +60,13 @@ def process(self, agent_process: Any, temperature: float = 0.0) -> None: Exception: For any other unexpected errors. """ assert re.search(r'claude', self.model_name, re.IGNORECASE), "Model name must contain 'claude'" - agent_process.set_status("executing") - agent_process.set_start_time(time.time()) - messages = agent_process.query.messages - tools = agent_process.query.tools + agent_request.set_status("executing") + agent_request.set_start_time(time.time()) + messages = agent_request.query.messages + tools = agent_request.query.tools self.logger.log(f"{messages}", level="info") - self.logger.log(f"{agent_process.agent_name} is switched to executing.", level="executing") + self.logger.log(f"{agent_request.agent_name} is switched to executing.", level="executing") if tools: messages = self.tool_calling_input_format(messages, tools) @@ -86,33 +86,50 @@ def process(self, agent_process: Any, temperature: float = 0.0) -> None: self.logger.log(f"API Response: {response_message}", level="info") tool_calls = self.parse_tool_calls(response_message) if tools else None - agent_process.set_response( - Response( - response_message=response_message, - tool_calls=tool_calls - ) + response = Response( + response_message=response_message, + tool_calls=tool_calls ) + + # agent_request.set_response( + # Response( + # response_message=response_message, + # tool_calls=tool_calls + # ) + # ) except anthropic.APIError as e: error_message = f"Anthropic API error: {str(e)}" self.logger.log(error_message, level="warning") - agent_process.set_response( - Response( - response_message=f"Error: {str(e)}", - tool_calls=None - ) + + response = Response( + response_message=f"Error: {str(e)}", + tool_calls=None ) + + # agent_request.set_response( + # Response( + # response_message=f"Error: {str(e)}", + # tool_calls=None + # ) + # ) + except Exception as e: error_message = f"Unexpected error: {str(e)}" self.logger.log(error_message, level="warning") - agent_process.set_response( - Response( - response_message=f"Unexpected error: {str(e)}", - tool_calls=None - ) + # agent_request.set_response( + # Response( + # response_message=f"Unexpected error: {str(e)}", + # tool_calls=None + # ) + # ) + response = Response( + response_message=f"Unexpected error: {str(e)}", + tool_calls=None ) - - agent_process.set_status("done") - agent_process.set_end_time(time.time()) + + return response + # agent_request.set_status("done") + # agent_request.set_end_time(time.time()) def _convert_to_anthropic_messages(self, messages: List[Dict[str, str]]) -> List[Dict[str, str]]: """ diff --git a/aios/llm_core/llm_classes/constant.py b/aios/llm_core/llm_classes/constant.py old mode 100755 new mode 100644 diff --git a/aios/llm_core/llm_classes/gemini_llm.py b/aios/llm_core/llm_classes/gemini_llm.py old mode 100755 new mode 100644 index 030e66993..eec3dc7a0 --- a/aios/llm_core/llm_classes/gemini_llm.py +++ b/aios/llm_core/llm_classes/gemini_llm.py @@ -50,17 +50,17 @@ def convert_messages(self, messages): return gemini_messages def process(self, - agent_process, + agent_request, temperature=0.0) -> None: # ensures the model is the current one """ wrapper around functions""" - agent_process.set_status("executing") - agent_process.set_start_time(time.time()) - messages = agent_process.query.messages - tools = agent_process.query.tools - message_return_type = agent_process.query.message_return_type + agent_request.set_status("executing") + agent_request.set_start_time(time.time()) + messages = agent_request.query.messages + tools = agent_request.query.tools + message_return_type = agent_request.query.message_return_type if tools: messages = self.tool_calling_input_format(messages, tools) @@ -71,7 +71,7 @@ def process(self, ) self.logger.log( - f"{agent_process.agent_name} is switched to executing.\n", + f"{agent_request.agent_name} is switched to executing.\n", level = "executing" ) @@ -84,28 +84,39 @@ def process(self, if tools: tool_calls = self.parse_tool_calls(result) if tool_calls: - agent_process.set_response( - Response( - response_message=None, - tool_calls=tool_calls - ) + # agent_request.set_response( + # Response( + # response_message=None, + # tool_calls=tool_calls + # ) + # ) + response = Response( + response_message=None, + tool_calls=tool_calls ) else: - agent_process.set_response( - Response( - response_message=result, - ) + # agent_request.set_response( + + # ) + response = Response( + response_message=result, ) else: if message_return_type == "json": result = self.parse_json_format(result) - agent_process.set_response( - Response( - response_message=result, - ) + + # agent_request.set_response( + # Response( + # response_message=result, + # ) + # ) + response = Response( + response_message=result, ) except IndexError: raise IndexError(f"{self.model_name} can not generate a valid result, please try again") - agent_process.set_status("done") - agent_process.set_end_time(time.time()) - return + + # agent_request.set_status("done") + # agent_request.set_end_time(time.time()) + # return + return response diff --git a/aios/llm_core/llm_classes/gpt_llm.py b/aios/llm_core/llm_classes/gpt_llm.py old mode 100755 new mode 100644 index 2b312a4d3..c5c54e1cc --- a/aios/llm_core/llm_classes/gpt_llm.py +++ b/aios/llm_core/llm_classes/gpt_llm.py @@ -10,18 +10,20 @@ from pyopenagi.utils.chat_template import Response import json + class GPTLLM(BaseLLM): - def __init__(self, llm_name: str, - max_gpu_memory: dict = None, - eval_device: str = None, - max_new_tokens: int = 1024, - log_mode: str = "console"): - super().__init__(llm_name, - max_gpu_memory, - eval_device, - max_new_tokens, - log_mode) + def __init__( + self, + llm_name: str, + max_gpu_memory: dict = None, + eval_device: str = None, + max_new_tokens: int = 1024, + log_mode: str = "console", + ): + super().__init__( + llm_name, max_gpu_memory, eval_device, max_new_tokens, log_mode + ) def load_llm_and_tokenizer(self) -> None: self.model = OpenAI() @@ -38,82 +40,63 @@ def parse_tool_calls(self, tool_calls): "name": function_name, "parameters": function_args, "type": tool_call.type, - "id": tool_call.id + "id": tool_call.id, } ) return parsed_tool_calls return None - def process(self, - agent_process, - temperature=0.0 - ): + def process(self, agent_request, temperature=0.0): # ensures the model is the current one - assert re.search(r'gpt', self.model_name, re.IGNORECASE) + assert re.search(r"gpt", self.model_name, re.IGNORECASE) """ wrapper around openai api """ - agent_process.set_status("executing") - agent_process.set_start_time(time.time()) - messages = agent_process.query.messages - # print(messages) - self.logger.log( - f"{agent_process.agent_name} is switched to executing.\n", - level = "executing" - ) - # time.sleep(10) + agent_request.set_status("executing") + agent_request.set_start_time(time.time()) + messages = agent_request.query.messages + try: response = self.model.chat.completions.create( model=self.model_name, - messages = messages, - tools = agent_process.query.tools, - # tool_choice = "required" if agent_process.query.tools else None, - max_tokens = self.max_new_tokens, - # response_format = {"type": "json_object"} + messages=messages, + tools=agent_request.query.tools, + # tool_choice = "required" if agent_request.query.tools else None, + max_tokens=self.max_new_tokens, ) - # print(response_message) response_message = response.choices[0].message.content - # print(response_message) - tool_calls = self.parse_tool_calls( - response.choices[0].message.tool_calls - ) + # print(f"[Response] {response}") + tool_calls = self.parse_tool_calls(response.choices[0].message.tool_calls) # print(tool_calls) # print(response.choices[0].message) - agent_process.set_response( - Response( - response_message = response_message, - tool_calls = tool_calls - ) + response = Response( + response_message=response_message, tool_calls=tool_calls ) + except openai.APIConnectionError as e: - agent_process.set_response( - Response( - response_message = f"Server connection error: {e.__cause__}" - ) + + response = Response( + response_message=f"Server connection error: {e.__cause__}" ) + except openai.RateLimitError as e: - agent_process.set_response( - Response( - response_message = f"OpenAI RATE LIMIT error {e.status_code}: (e.response)" - ) + + response = Response( + response_message=f"OpenAI RATE LIMIT error {e.status_code}: (e.response)" ) + except openai.APIStatusError as e: - agent_process.set_response( - Response( - response_message = f"OpenAI STATUS error {e.status_code}: (e.response)" - ) + response = Response( + response_message=f"OpenAI STATUS error {e.status_code}: (e.response)" ) + except openai.BadRequestError as e: - agent_process.set_response( - Response( - response_message = f"OpenAI BAD REQUEST error {e.status_code}: (e.response)" - ) + + response = Response( + response_message=f"OpenAI BAD REQUEST error {e.status_code}: (e.response)" ) + except Exception as e: - agent_process.set_response( - Response( - response_message = f"An unexpected error occurred: {e}" - ) - ) + response = Response(response_message=f"An unexpected error occurred: {e}") - agent_process.set_status("done") - agent_process.set_end_time(time.time()) + return response + \ No newline at end of file diff --git a/aios/llm_core/llm_classes/groq_llm.py b/aios/llm_core/llm_classes/groq_llm.py index 692791670..d9164168c 100644 --- a/aios/llm_core/llm_classes/groq_llm.py +++ b/aios/llm_core/llm_classes/groq_llm.py @@ -48,7 +48,7 @@ def parse_tool_calls(self, tool_calls): return None def process(self, - agent_process, + agent_request, temperature=0.0 ): # ensures the model is the current one @@ -56,65 +56,57 @@ def process(self, # assert re.search(r'gpt', self.model_name, re.IGNORECASE) """ wrapper around openai api """ - agent_process.set_status("executing") - agent_process.set_start_time(time.time()) - messages = agent_process.query.messages + agent_request.set_status("executing") + agent_request.set_start_time(time.time()) + messages = agent_request.query.messages # print(messages) self.logger.log( - f"{agent_process.agent_name} is switched to executing.\n", + f"{agent_request.agent_name} is switched to executing.\n", level = "executing" ) - time.sleep(2) + # time.sleep(2) try: response = self.model.chat.completions.create( model=self.model_name, messages = messages, - tools = agent_process.query.tools, - # tool_choice = "required" if agent_process.query.tools else None, + tools = agent_request.query.tools, + # tool_choice = "required" if agent_request.query.tools else None, max_tokens = self.max_new_tokens ) response_message = response.choices[0].message.content tool_calls = self.parse_tool_calls( response.choices[0].message.tool_calls ) - # print(tool_calls) - # print(response.choices[0].message) - agent_process.set_response( - Response( - response_message = response_message, - tool_calls = tool_calls - ) + + response = Response( + response_message = response_message, + tool_calls = tool_calls ) + except openai.APIConnectionError as e: - agent_process.set_response( - Response( - response_message = f"Server connection error: {e.__cause__}" - ) + response = Response( + response_message = f"Server connection error: {e.__cause__}" ) + except openai.RateLimitError as e: - agent_process.set_response( - Response( - response_message = f"OpenAI RATE LIMIT error {e.status_code}: (e.response)" - ) + response = Response( + response_message = f"OpenAI RATE LIMIT error {e.status_code}: (e.response)" ) + except openai.APIStatusError as e: - agent_process.set_response( - Response( - response_message = f"OpenAI STATUS error {e.status_code}: (e.response)" - ) + response = Response( + response_message = f"OpenAI STATUS error {e.status_code}: (e.response)" ) + except openai.BadRequestError as e: - agent_process.set_response( - Response( - response_message = f"OpenAI BAD REQUEST error {e.status_code}: (e.response)" - ) + response = Response( + response_message = f"OpenAI BAD REQUEST error {e.status_code}: (e.response)" ) + except Exception as e: - agent_process.set_response( - Response( - response_message = f"An unexpected error occurred: {e}" - ) + response = Response( + response_message = f"An unexpected error occurred: {e}" ) - agent_process.set_status("done") - agent_process.set_end_time(time.time()) + return response + \ No newline at end of file diff --git a/aios/llm_core/llm_classes/hf_native_llm.py b/aios/llm_core/llm_classes/hf_native_llm.py old mode 100755 new mode 100644 index b0fbb5c4f..5be371158 --- a/aios/llm_core/llm_classes/hf_native_llm.py +++ b/aios/llm_core/llm_classes/hf_native_llm.py @@ -39,23 +39,23 @@ def parse_tool_callings(self, result): return matches[-1] def process(self, - agent_process, + agent_request, temperature=0.0) -> None: - agent_process.set_status("executing") - agent_process.set_start_time(time.time()) + agent_request.set_status("executing") + agent_request.set_start_time(time.time()) self.logger.log( - f"{agent_process.agent_name} is switched to executing.\n", + f"{agent_request.agent_name} is switched to executing.\n", level = "executing" ) - messages = agent_process.query.messages - tools = agent_process.query.tools - message_return_type = agent_process.query.message_return_type + messages = agent_request.query.messages + tools = agent_request.query.tools + message_return_type = agent_request.query.message_return_type """ context_manager works only with open llms """ - if self.context_manager.check_restoration(agent_process.get_pid()): + if self.context_manager.check_restoration(agent_request.get_pid()): restored_context = self.context_manager.gen_recover( - agent_process.get_pid() + agent_request.get_pid() ) start_idx = restored_context["start_idx"] beams = restored_context["beams"] @@ -70,7 +70,7 @@ def process(self, beam_attention_mask = beam_attention_mask, max_new_tokens = self.max_new_tokens, start_idx = start_idx, - timestamp = agent_process.get_time_limit() + timestamp = agent_request.get_time_limit() ) else: """ use the system prompt otherwise """ @@ -96,7 +96,7 @@ def process(self, beam_size = 1, max_new_tokens=self.max_new_tokens, start_idx = 0, - timestamp = agent_process.get_time_limit() + timestamp = agent_request.get_time_limit() ) # TODO temporarily outputs["result"] = outputs["result"][input_ids.shape[-1]:] @@ -110,37 +110,37 @@ def process(self, if outputs["finished_flag"]: # finished flag is set as True if self.context_manager.check_restoration( - agent_process.get_pid()): + agent_request.get_pid()): self.context_manager.clear_restoration( - agent_process.get_pid() + agent_request.get_pid() ) if tools: tool_calls = self.parse_tool_calls( result ) - agent_process.set_response( + agent_request.set_response( Response( response_message = None, tool_calls = tool_calls ) ) else: - agent_process.set_response( + agent_request.set_response( Response( response_message = result ) ) - agent_process.set_status("done") + agent_request.set_status("done") else: """ the module will automatically suspend if reach the time limit """ self.logger.log( - f"{agent_process.agent_name} is switched to suspending due to the reach of time limit ({agent_process.get_time_limit()}s).\n", + f"{agent_request.agent_name} is switched to suspending due to the reach of time limit ({agent_request.get_time_limit()}s).\n", level = "suspending" ) self.context_manager.gen_snapshot( - agent_process.get_pid(), + agent_request.get_pid(), context = { "start_idx": outputs["start_idx"], "beams": outputs["beams"], @@ -150,14 +150,14 @@ def process(self, ) if message_return_type == "json": result = self.parse_json_format(result) - agent_process.set_response( + agent_request.set_response( Response( response_message = result ) ) - agent_process.set_status("suspending") + agent_request.set_status("suspending") - agent_process.set_end_time(time.time()) + agent_request.set_end_time(time.time()) def generate(self, input_ids: torch.Tensor = None, diff --git a/aios/llm_core/llm_classes/model_registry.py b/aios/llm_core/llm_classes/model_registry.py old mode 100755 new mode 100644 diff --git a/aios/llm_core/llm_classes/ollama_llm.py b/aios/llm_core/llm_classes/ollama_llm.py old mode 100755 new mode 100644 index c632a5d2b..e15db4f49 --- a/aios/llm_core/llm_classes/ollama_llm.py +++ b/aios/llm_core/llm_classes/ollama_llm.py @@ -26,20 +26,20 @@ def load_llm_and_tokenizer(self) -> None: self.tokenizer = None def process(self, - agent_process, + agent_request, temperature=0.0 ): # ensures the models are from ollama assert re.search(r'ollama', self.model_name, re.IGNORECASE) """ simple wrapper around ollama functions """ - agent_process.set_status("executing") - agent_process.set_start_time(time.time()) - messages = agent_process.query.messages - tools = agent_process.query.tools - message_return_type = agent_process.query.message_return_type + agent_request.set_status("executing") + agent_request.set_start_time(time.time()) + messages = agent_request.query.messages + tools = agent_request.query.tools + message_return_type = agent_request.query.message_return_type self.logger.log( - f"{agent_process.agent_name} is switched to executing.\n", + f"{agent_request.agent_name} is switched to executing.\n", level = "executing" ) @@ -57,20 +57,20 @@ def process(self, ) if tool_calls: - agent_process.set_response( + agent_request.set_response( Response( response_message = None, tool_calls = tool_calls ) ) else: - agent_process.set_response( + agent_request.set_response( Response( response_message = response['message']['content'] ) ) except Exception as e: - agent_process.set_response( + agent_request.set_response( Response( response_message = f"An unexpected error occurred: {e}" ) @@ -92,19 +92,19 @@ def process(self, if message_return_type == "json": result = self.parse_json_format(result) - agent_process.set_response( + agent_request.set_response( Response( response_message = result ) ) except Exception as e: - agent_process.set_response( + agent_request.set_response( Response( response_message = f"An unexpected error occurred: {e}" ) ) - agent_process.set_status("done") - agent_process.set_end_time(time.time()) + agent_request.set_status("done") + agent_request.set_end_time(time.time()) return diff --git a/aios/llm_core/llm_classes/vllm.py b/aios/llm_core/llm_classes/vllm.py old mode 100755 new mode 100644 index 848e86156..8618bfaae --- a/aios/llm_core/llm_classes/vllm.py +++ b/aios/llm_core/llm_classes/vllm.py @@ -52,18 +52,18 @@ def load_llm_and_tokenizer(self) -> None: ) def process(self, - agent_process, + agent_request, temperature=0.0) -> None: - agent_process.set_status("executing") - agent_process.set_start_time(time.time()) + agent_request.set_status("executing") + agent_request.set_start_time(time.time()) self.logger.log( - f"{agent_process.agent_name} is switched to executing.\n", + f"{agent_request.agent_name} is switched to executing.\n", level = "executing" ) - messages = agent_process.query.messages - tools = agent_process.query.tools - message_return_type = agent_process.query.message_return_type + messages = agent_request.query.messages + tools = agent_request.query.tools + message_return_type = agent_request.query.message_return_type if tools: messages = self.tool_calling_input_format(messages, tools) @@ -86,14 +86,14 @@ def process(self, result ) if tool_calls: - agent_process.set_response( + agent_request.set_response( Response( response_message = None, tool_calls = tool_calls ) ) else: - agent_process.set_response( + agent_request.set_response( Response( response_message = result ) @@ -114,12 +114,12 @@ def process(self, if message_return_type == "json": result = self.parse_json_format(result) - agent_process.set_response( + agent_request.set_response( Response( response_message=result ) ) - agent_process.set_status("done") + agent_request.set_status("done") - agent_process.set_end_time(time.time()) + agent_request.set_end_time(time.time()) diff --git a/aios/llm_core/llms.py b/aios/llm_core/llms.py index 3e801d052..614aae49f 100644 --- a/aios/llm_core/llms.py +++ b/aios/llm_core/llms.py @@ -30,7 +30,6 @@ def __init__(self, use_backend: str = None ): - # For API-based LLM if llm_name in MODEL_REGISTRY.keys(): self.model = MODEL_REGISTRY[llm_name]( @@ -66,12 +65,12 @@ def __init__(self, ) def address_request(self, - agent_process, + agent_request, temperature=0.0) -> None: """Address request sent from the agent Args: - agent_process: AgentProcess object that contains request sent from the agent + agent_request: AgentProcess object that contains request sent from the agent temperature (float, optional): Parameter to control the randomness of LLM output. Defaults to 0.0. """ - self.model.address_request(agent_process,temperature) + return self.model.address_request(agent_request, temperature) diff --git a/aios/scheduler/fifo_scheduler.py b/aios/scheduler/fifo_scheduler.py index 1652b4a01..deabb15b5 100644 --- a/aios/scheduler/fifo_scheduler.py +++ b/aios/scheduler/fifo_scheduler.py @@ -19,24 +19,41 @@ def __init__(self, llm, log_mode, get_queue_message: QueueGetMessage): def run(self): while self.active: try: - """ - wait at a fixed time interval - if there is nothing received in the time interval, it will raise Empty - """ - - agent_process = self.get_queue_message() - agent_process.set_status("executing") - self.logger.log(f"{agent_process.agent_name} is executing. \n", "execute") - agent_process.set_start_time(time.time()) - self.execute_request(agent_process) - self.logger.log(f"Current request of {agent_process.agent_name} is done. Thread ID is {agent_process.get_pid()}\n", "done") + # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty + agent_request = self.get_queue_message() + + agent_request.set_status("executing") + self.logger.log( + f"{agent_request.agent_name} is executing. \n", "execute" + ) + agent_request.set_start_time(time.time()) + + self.execute_request(agent_request) + + self.logger.log( + f"Current request of {agent_request.agent_name} is done. Thread ID is {agent_request.get_pid()}\n", "done" + ) except Empty: pass + except Exception: traceback.print_exc() - def execute_request(self, agent_process): - self.llm.address_request( - agent_process=agent_process - ) + def execute_request(self, agent_request): + action_type = agent_request.query.action_type + + response = self.llm.address_request(agent_request) + + if action_type == "message_llm": + agent_request.set_response(response) + + # self.llm.address_request(agent_request) + + # elif action_type == "operate_file": + # api_calls = self.lsfs_parser.parse(agent_request) + # response = self.lsfs.execute_calls(api_calls) + # agent_request.set_response(response) + + agent_request.set_status("done") + agent_request.set_end_time(time.time()) diff --git a/pyopenagi/utils/chat_template.py b/pyopenagi/utils/chat_template.py index 2349c7d3c..ae63f8ce8 100755 --- a/pyopenagi/utils/chat_template.py +++ b/pyopenagi/utils/chat_template.py @@ -2,7 +2,8 @@ class Query: def __init__(self, messages, tools = None, - message_return_type = "json" + action_type: str = "message_llm", + message_return_type = "text" ) -> None: """Query format @@ -15,6 +16,7 @@ def __init__(self, """ self.messages = messages self.tools = tools + self.action_type = action_type self.message_return_type = message_return_type class Response: From 8f6841ce3ff5e17e0c9639ff709898f75b70656b Mon Sep 17 00:00:00 2001 From: dongyuanjushi Date: Mon, 7 Oct 2024 15:00:26 -0400 Subject: [PATCH 02/41] update query response format --- pyopenagi/utils/chat_template.py | 73 ++++++++++++++++---------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/pyopenagi/utils/chat_template.py b/pyopenagi/utils/chat_template.py index ae63f8ce8..285b46427 100755 --- a/pyopenagi/utils/chat_template.py +++ b/pyopenagi/utils/chat_template.py @@ -1,39 +1,40 @@ -class Query: - def __init__(self, - messages, - tools = None, - action_type: str = "message_llm", - message_return_type = "text" - ) -> None: - """Query format +from pydantic import BaseModel, Field +from typing import List, Dict, Optional, Any, Union +from typing_extensions import Literal # Import Literal from typing_extensions for stricter typing - Args: - messages (list): - [ - {"role": "xxx", content_key: content_value} - ] - tools (optional): tools that are used for function calling. Defaults to None. - """ - self.messages = messages - self.tools = tools - self.action_type = action_type - self.message_return_type = message_return_type +class Query(BaseModel): + """ + Query class represents the input structure for performing various actions. + + Attributes: + messages (List[Dict[str, Union[str, Any]]]): A list of dictionaries where each dictionary + represents a message containing 'role' and 'content' or other key-value pairs. + tools (Optional[List[Dict[str, Any]]]): An optional list of JSON-like objects (dictionaries) + representing tools and their parameters. Default is an empty list. + action_type (Literal): A string that must be one of "message_llm", "call_tool", or "operate_file". + This restricts the type of action the query performs. + message_return_type (str): The type of the response message. Default is "text". + """ + messages: List[Dict[str, Union[str, Any]]] # List of message dictionaries, each containing role and content. + tools: Optional[List[Dict[str, Any]]] = Field(default_factory=list) # List of JSON-like objects (dictionaries) representing tools. + action_type: Literal["message_llm", "call_tool", "operate_file"] = Field(default="message_llm") # Restrict the action_type to specific choices. + message_return_type: str = Field(default="text") # Type of the return message, default is "text". -class Response: - def __init__( - self, - response_message, - tool_calls: list = None - ) -> None: - """Response format + class Config: + arbitrary_types_allowed = True # Allows the use of arbitrary types such as Any and Dict. - Args: - response_message (str): "generated_text" - tool_calls (list, optional): - [ - {"name": "xxx", "parameters": {}} - ]. - Default to None. - """ - self.response_message = response_message - self.tool_calls = tool_calls + +class Response(BaseModel): + """ + Response class represents the output structure after performing actions. + + Attributes: + response_message (Optional[str]): The generated response message. Default is None. + tool_calls (Optional[List[Dict[str, Any]]]): An optional list of JSON-like objects (dictionaries) + representing the tool calls made during processing. Default is None. + """ + response_message: Optional[str] = None # The generated response message, default is None. + tool_calls: Optional[List[Dict[str, Any]]] = None # List of JSON-like objects representing tool calls, default is None. + + class Config: + arbitrary_types_allowed = True # Allows arbitrary types in validation. From cd9f892b657a5bbe44a0bd7a664671252162417c Mon Sep 17 00:00:00 2001 From: dongyuanjushi Date: Mon, 7 Oct 2024 16:23:00 -0400 Subject: [PATCH 03/41] update --- aios/hooks/llm.py | 5 +- aios/hooks/request.py | 147 +++++++ aios/hooks/types/llm.py | 6 +- main.py | 72 ++-- pyopenagi/agents/agent_factory.py | 6 +- pyopenagi/agents/agent_process.py | 170 -------- pyopenagi/agents/base_agent.py | 130 +----- .../agents/example/academic_agent/agent.py | 392 +++++++++++++++++- .../agents/example/academic_agent/config.json | 2 +- pyopenagi/agents/react_agent.py | 162 +------- 10 files changed, 599 insertions(+), 493 deletions(-) create mode 100755 aios/hooks/request.py delete mode 100755 pyopenagi/agents/agent_process.py diff --git a/aios/hooks/llm.py b/aios/hooks/llm.py index 04b47ff11..87cfbfa91 100644 --- a/aios/hooks/llm.py +++ b/aios/hooks/llm.py @@ -17,7 +17,6 @@ from aios.hooks.utils import generate_random_string from pyopenagi.agents.agent_factory import AgentFactory -from pyopenagi.agents.agent_process import AgentProcessFactory ids = [] @@ -65,10 +64,10 @@ def stopScheduler(): @validate(FactoryParams) def useFactory(params: FactoryParams): - process_factory = AgentProcessFactory() + # process_factory = AgentProcessFactory() agent_factory = AgentFactory( - agent_process_factory=process_factory, + # agent_process_factory=process_factory, agent_log_mode=params.log_mode, ) diff --git a/aios/hooks/request.py b/aios/hooks/request.py new file mode 100755 index 000000000..19e964a8a --- /dev/null +++ b/aios/hooks/request.py @@ -0,0 +1,147 @@ +from threading import Thread, Lock +from typing import Mapping + +import random +import time +from aios.hooks.stores._global import global_llm_req_queue_add_message + + +class AgentRequest(Thread): + def __init__(self, agent_name, query): + """Agent Process + + Args: + agent_name (str): Name of the agent + query (Query): Query sent by the agent + """ + super().__init__(name=agent_name) + self.agent_name = agent_name + self.query = query + self.pid: int = None + self.status = None + self.response = None + self.time_limit = None + self.created_time = None + self.start_time = None + self.end_time = None + + def set_created_time(self, time): + self.created_time = time + + def get_created_time(self): + return self.created_time + + def set_start_time(self, time): + self.start_time = time + + def get_start_time(self): + return self.start_time + + def set_end_time(self, time): + self.end_time = time + + def get_end_time(self): + return self.end_time + + def set_priority(self, priority): + self.priority = priority + + def get_priority(self): + return self.priority + + def set_status(self, status): + self.status = status + + def get_status(self): + return self.status + + def set_aid(self, aid): + self.aid = aid + + def get_aid(self): + return self.pid + + def set_pid(self, pid): + self.pid = pid + + def get_pid(self): + return self.pid + + def get_response(self): + return self.response + + def set_response(self, response): + self.response = response + + def get_time_limit(self): + return self.time_limit + + def set_time_limit(self, time_limit): + self.time_limit = time_limit + + def run(self): + """Response Listener for agent + + Args: + agent_process (AgentProcess): Listened AgentProcess + + Returns: + str: LLM response of Agent Process + """ + self.set_pid(self.native_id) + while self.get_response() is None: + time.sleep(0.1) + + return self.get_response() + + +class LLMRequest(AgentRequest): + pass + + +def send_request(agent_name, query): + agent_request = AgentRequest( + agent_name=agent_name, + query=query + ) + agent_request.set_status("active") + + completed_response, start_times, end_times, waiting_times, turnaround_times = ( + "", + [], + [], + [], + [], + ) + + while agent_request.get_status() != "done": + current_time = time.time() + agent_request.set_created_time(current_time) + agent_request.set_response(None) + + global_llm_req_queue_add_message(agent_request) + + agent_request.start() + agent_request.join() + + completed_response = agent_request.get_response() + + if agent_request.get_status() != "done": + pass + start_time = agent_request.get_start_time() + end_time = agent_request.get_end_time() + waiting_time = start_time - agent_request.get_created_time() + turnaround_time = end_time - agent_request.get_created_time() + + start_times.append(start_time) + end_times.append(end_time) + waiting_times.append(waiting_time) + turnaround_times.append(turnaround_time) + + return ( + completed_response, + start_times, + end_times, + waiting_times, + turnaround_times, + ) \ No newline at end of file diff --git a/aios/hooks/types/llm.py b/aios/hooks/types/llm.py index 1d4aeafc1..70224a5cb 100644 --- a/aios/hooks/types/llm.py +++ b/aios/hooks/types/llm.py @@ -3,11 +3,9 @@ from queue import Queue -from pyopenagi.agents.agent_process import AgentProcess +LLMRequestQueue: TypeAlias = Queue -LLMRequestQueue: TypeAlias = Queue[AgentProcess] - -QueueGetMessage: TypeAlias = Callable[[], AgentProcess] +QueueGetMessage: TypeAlias = Callable[[], None] QueueAddMessage: TypeAlias = Callable[[str], None] QueueCheckEmpty: TypeAlias = Callable[[], bool] diff --git a/main.py b/main.py index 09f513c42..083d042e1 100644 --- a/main.py +++ b/main.py @@ -35,44 +35,52 @@ def main(): with aios_starter(**vars(args)) as (submit_agent, await_agent_execution): # register your agents and submit agent tasks - """ submitAgent( - agent_name="example/academic_agent", - task_input="Find recent papers on the impact of social media on mental health in adolescents." - ) - """ - - """ - submitAgent( - agent_name="om-raheja/transcribe_agent", - task_input="listen to my yap for 5 seconds and write a response to it" - ) - """ - - """ - submitAgent( - agent_name="example/cocktail_mixlogist", - task_input="Create a cocktail for a summer garden party. Guests enjoy refreshing, citrusy flavors. Available ingredients include vodka, gin, lime, lemon, mint, and various fruit juices." - ) - """ - - """ - submitAgent( - agent_name="example/cook_therapist", - task_input="Develop a low-carb, keto-friendly dinner that is flavorful and satisfying." - ) - """ agent_tasks = [ - ["example/academic_agent", "Tell me what is the prollm paper mainly about"] - # ["example/cocktail_mixlogist", "Create a cocktail for a summer garden party. Guests enjoy refreshing, citrusy flavors. Available ingredients include vodka, gin, lime, lemon, mint, and various fruit juices."] + ["example/academic_agent", "Tell me what is the prollm paper mainly about"], + # [ + # "example/cocktail_mixlogist", + # "Create a cocktail for a summer garden party. Guests enjoy refreshing, citrusy flavors. Available ingredients include vodka, gin, lime, lemon, mint, and various fruit juices.", + # ], + # [ + # "example/festival_card_designer", + # "Design a festival card for a vintage-themed music festival targeting young adults, with a square card size.", + # ], + # [ + # "example/logo_creator", + # "Design a minimalist logo for a tech startup specializing in AI-powered cybersecurity solutions.", + # ], + # [ + # "example/story_teller", + # "Create a dystopian short story featuring a protagonist with a unique biological adaptation, exploring themes of societal oppression and rebellion.", + # ], + # [ + # "example/interior_decorator", + # "I want to transform my small, dark living room into a bright and airy space. I love minimalist Scandinavian design and prefer neutral colors. Can you help me?", + # ], + # ["example/math_agent", "Solve the equation: 2^(3x-1) = 5^(x+2)."], + # [ + # "example/cook_therapist", + # "Develop a low-carb, keto-friendly dinner that is flavorful and satisfying.", + # ], + # ["example/meme_creator", "Create a meme about the struggles of adulting."], + # [ + # "example/fitness_trainer", + # "Create a workout plan for a busy professional aiming to lose 10 pounds in 3 months.", + # ], + # [ + # "example/music_composer", + # "Compose a dreamy indie-pop song with a catchy chorus.", + # ], + # [ + # "example/creation_agent", + # "Create an Instagram post: Image of a person using a new tech gadget, text highlighting its key features and benefits.", + # ], ] agent_ids = [] for agent_name, task_input in agent_tasks: - agent_id = submit_agent( - agent_name=agent_name, - task_input=task_input - ) + agent_id = submit_agent(agent_name=agent_name, task_input=task_input) agent_ids.append(agent_id) for agent_id in agent_ids: diff --git a/pyopenagi/agents/agent_factory.py b/pyopenagi/agents/agent_factory.py index 4e06bde5b..cc2cbf5ca 100755 --- a/pyopenagi/agents/agent_factory.py +++ b/pyopenagi/agents/agent_factory.py @@ -9,7 +9,7 @@ class AgentFactory: def __init__(self, # agent_process_queue, - agent_process_factory, + # agent_process_factory, agent_log_mode ): self.max_aid = 256 @@ -17,7 +17,7 @@ def __init__(self, self.aid_pool = [i for i in range(self.max_aid)] heapq.heapify(self.aid_pool) # self.agent_process_queue = agent_process_queue - self.agent_process_factory = agent_process_factory + # self.agent_process_factory = agent_process_factory self.current_agents = {} @@ -68,7 +68,7 @@ def activate_agent(self, agent_name: str, task_input): agent = agent_class( agent_name = agent_name, task_input = task_input, - agent_process_factory = self.agent_process_factory, + # agent_process_factory = self.agent_process_factory, log_mode = self.agent_log_mode ) diff --git a/pyopenagi/agents/agent_process.py b/pyopenagi/agents/agent_process.py deleted file mode 100755 index 001b972a5..000000000 --- a/pyopenagi/agents/agent_process.py +++ /dev/null @@ -1,170 +0,0 @@ -from threading import Thread, Lock -from typing import Mapping -import threading - -from ..utils.chat_template import Query -import random -import time -import os - -class AgentProcess(Thread): - def __init__(self, agent_name: str, query: Query): - """Agent Process - - Args: - agent_name (str): Name of the agent - query (Query): Query sent by the agent - """ - super().__init__(name=agent_name) - self.agent_name = agent_name - self.query = query - self.pid: int = None - self.status = None - self.response = None - self.time_limit = None - self.created_time = None - self.start_time = None - self.end_time = None - - def set_created_time(self, time): - self.created_time = time - - def get_created_time(self): - return self.created_time - - def set_start_time(self, time): - self.start_time = time - - def get_start_time(self): - return self.start_time - - def set_end_time(self, time): - self.end_time = time - - def get_end_time(self): - return self.end_time - - def set_priority(self, priority): - self.priority = priority - - def get_priority(self): - return self.priority - - def set_status(self, status): - self.status = status - - def get_status(self): - return self.status - - def set_aid(self, aid): - self.aid = aid - - def get_aid(self): - return self.pid - - def set_pid(self, pid): - self.pid = pid - - def get_pid(self): - return self.pid - - def get_response(self): - return self.response - - def set_response(self, response): - self.response = response - - def get_time_limit(self): - return self.time_limit - - def set_time_limit(self, time_limit): - self.time_limit = time_limit - - def run(self): - """Response Listener for agent - - Args: - agent_process (AgentProcess): Listened AgentProcess - - Returns: - str: LLM response of Agent Process - """ - self.set_pid(self.native_id) - while self.get_response() is None: - time.sleep(0.1) - - return self.get_response() - - -class LLMRequestProcess(AgentProcess): - pass - - -class AgentProcessFactory: - def __init__(self, agent_process_log_mode=None): - # self.max_pid = 1024 - # self.pid_pool = [i for i in range(self.max_pid)] - # heapq.heapify(self.pid_pool) - - # self.thread = Thread(target=self.deactivate_agent_process) - - self.current_agent_processes = dict() - - self.current_agent_processes_lock = Lock() - - # self.terminate_signal = Event() - - self.agent_process_log_mode = agent_process_log_mode - - def activate_agent_process(self, agent_name, query): - # if not self.terminate_signal.is_set(): - with self.current_agent_processes_lock: - agent_process = AgentProcess(agent_name=agent_name, query=query) - # pid = heapq.heappop(self.pid_pool) - # agent_process.set_pid(pid) - agent_process.set_status("active") - # self.current_agent_processes[pid] = agent_process - return agent_process - - def print_agent_process(self): - headers = ["Agent Process ID", "Agent Name", "Created Time", "Status"] - data = [] - for id, agent_process in self.current_agent_processes.items(): - agent_name = agent_process.agent_name - created_time = agent_process.created_time - status = agent_process.status - # memory_usage = f"{asizeof.asizeof(agent)} bytes" - data.append([id, agent_name, created_time, status]) - self.print(headers=headers, data=data) - - def print(self, headers, data): - # align output - column_widths = [ - max(len(str(row[i])) for row in [headers] + data) - for i in range(len(headers)) - ] - print("+" + "-" * (sum(column_widths) + len(headers) * 3 - 3) + "+") - print(self.format_row(headers, column_widths)) - print("=" * (sum(column_widths) + len(headers) * 3 - 1)) - for i, row in enumerate(data): - print(self.format_row(row, column_widths)) - if i < len(data): - print("-" * (sum(column_widths) + len(headers) * 3 - 1)) - print("+" + "-" * (sum(column_widths) + len(headers) * 3 - 3) + "+") - - def format_row(self, row, widths, align="<"): - row_str = " | ".join( - f"{str(item):{align}{widths[i]}}" for i, item in enumerate(row) - ) - return row_str - - def deactivate_agent_process(self, pid): - self.current_agent_processes.pop(pid) - # heapq.heappush(self.pid_pool, pid) - - def start(self): - """start the factory to check inactive agent""" - self.thread.start() - - def stop(self): - self.thread.join() diff --git a/pyopenagi/agents/base_agent.py b/pyopenagi/agents/base_agent.py index a509c6bae..8e70f27ff 100755 --- a/pyopenagi/agents/base_agent.py +++ b/pyopenagi/agents/base_agent.py @@ -2,12 +2,6 @@ import json -from pyopenagi.manager.manager import AgentManager - -from .agent_process import ( - AgentProcess -) - import time from threading import Thread @@ -20,43 +14,19 @@ import importlib -from aios.hooks.stores._global import global_llm_req_queue_add_message - - -class CustomizedThread(Thread): - def __init__(self, target, args=()): - super().__init__() - self.target = target - self.args = args - self.result = None - - def run(self): - self.result = self.target(*self.args) - - def join(self): - super().join() - return self.result - +from aios.hooks.request import send_request class BaseAgent: - def __init__(self, agent_name, task_input, agent_process_factory, log_mode: str): + def __init__(self, agent_name, task_input, log_mode: str): # super().__init__() self.agent_name = agent_name - self.manager = AgentManager('https://my.aios.foundation/') - - author, name, version = self.agent_name.split('/') - - path_version = self.manager._version_to_path(version) - - self.config = self.manager._get_agent_metadata( - f'{self.manager.cache_dir / author / name / path_version}') - - print(self.config) - - # self.config = self.load_config() + self.config = self.load_config() self.tool_names = self.config["tools"] + + self.plan_max_fail_times = 3 + self.tool_call_max_fail_times = 3 - self.agent_process_factory = agent_process_factory + # self.agent_process_factory = agent_process_factory self.tool_list = dict() self.tools = [] @@ -84,7 +54,10 @@ def __init__(self, agent_name, task_input, agent_process_factory, log_mode: str) def run(self): """Execute each step to finish the task.""" # self.set_aid(threading.get_ident()) - self.logger.log(f"{self.agent_name} starts running. Agent ID is {self.get_aid()}\n", level="info") + self.logger.log( + f"{self.agent_name} starts running. Agent ID is {self.get_aid()}\n", + level="info", + ) # can be customization def build_system_instruction(self): @@ -108,11 +81,10 @@ def check_workflow(self, message): def automatic_workflow(self): for i in range(self.plan_max_fail_times): - response, start_times, end_times, waiting_times, turnaround_times = ( - self.get_response( - query=Query( - messages=self.messages, tools=None, message_return_type="json" - ) + response, start_times, end_times, waiting_times, turnaround_times = send_request( + agent_name = self.agent_name, + query=Query( + messages=self.messages, tools=None, message_return_type="json" ) ) @@ -166,13 +138,17 @@ def snake_to_camel(self, snake_str): return "".join(x.title() for x in components) def load_tools(self, tool_names): + if tool_names == "None": + return for tool_name in tool_names: org, name = tool_name.split("/") module_name = ".".join(["pyopenagi", "tools", org, name]) class_name = self.snake_to_camel(name) + tool_module = importlib.import_module(module_name) tool_class = getattr(tool_module, class_name) + self.tool_list[name] = tool_class() tool_format = tool_class().get_tool_call_format() self.tools.append(tool_format) @@ -205,74 +181,6 @@ def load_config(self): config = json.load(f) return config - # the default method used for getting response from AIOS - def get_response(self, query, temperature=0.0): - - # thread = CustomizedThread(target=self.query_loop, args=(query, )) - # thread.start() - # return thread.join() - return self.query_loop(query) - - def query_loop(self, query): - agent_process = self.create_agent_request(query) - - completed_response, start_times, end_times, waiting_times, turnaround_times = ( - "", - [], - [], - [], - [], - ) - - while agent_process.get_status() != "done": - # thread = Thread(target=self.listen, args=(agent_process, )) - current_time = time.time() - # reinitialize agent status - agent_process.set_created_time(current_time) - agent_process.set_response(None) - - global_llm_req_queue_add_message(agent_process) - - # thread.start() - # thread.join() - agent_process.start() - agent_process.join() - - completed_response = agent_process.get_response() - if agent_process.get_status() != "done": - self.logger.log( - f"Suspended due to the reach of time limit ({agent_process.get_time_limit()}s). Current result is: {completed_response.response_message}\n", - level="suspending", - ) - start_time = agent_process.get_start_time() - end_time = agent_process.get_end_time() - waiting_time = start_time - agent_process.get_created_time() - turnaround_time = end_time - agent_process.get_created_time() - - start_times.append(start_time) - end_times.append(end_time) - waiting_times.append(waiting_time) - turnaround_times.append(turnaround_time) - # Re-start the thread if not done - - # self.agent_process_factory.deactivate_agent_process(agent_process.get_pid()) - - return ( - completed_response, - start_times, - end_times, - waiting_times, - turnaround_times, - ) - - def create_agent_request(self, query): - agent_process = self.agent_process_factory.activate_agent_process( - agent_name=self.agent_name, query=query - ) - agent_process.set_created_time(time.time()) - # print("Already put into the queue") - return agent_process - def set_aid(self, aid): self.aid = aid diff --git a/pyopenagi/agents/example/academic_agent/agent.py b/pyopenagi/agents/example/academic_agent/agent.py index 23663a569..cafc614b6 100644 --- a/pyopenagi/agents/example/academic_agent/agent.py +++ b/pyopenagi/agents/example/academic_agent/agent.py @@ -1,14 +1,49 @@ -from pyopenagi.agents.react_agent import ReactAgent +import importlib + import os +import time +from aios.hooks.request import send_request -class AcademicAgent(ReactAgent): - def __init__(self, agent_name, task_input, agent_process_factory, log_mode: str): - ReactAgent.__init__( - self, agent_name, task_input, agent_process_factory, log_mode - ) - self.workflow_mode = "manual" - # self.workflow_mode = "automatic" +from pyopenagi.utils.chat_template import Query + +from pyopenagi.utils.logger import AgentLogger + +import json + +class AcademicAgent: + def __init__(self, agent_name, task_input, log_mode: str): + self.agent_name = agent_name + self.config = self.load_config() + self.tool_names = self.config["tools"] + + self.plan_max_fail_times = 3 + self.tool_call_max_fail_times = 3 + + # self.agent_process_factory = agent_process_factory + + self.tool_list = dict() + self.tools = [] + self.tool_info = ( + [] + ) # simplified information of the tool: {"name": "xxx", "description": "xxx"} + + self.load_tools(self.tool_names) + + self.start_time = None + self.end_time = None + self.request_waiting_times: list = [] + self.request_turnaround_times: list = [] + self.task_input = task_input + self.messages = [] + self.workflow_mode = "manual" # (mannual, automatic) + self.rounds = 0 + + self.log_mode = log_mode + self.logger = self.setup_logger() + + self.set_status("active") + self.set_created_time(time.time()) def check_path(self, tool_calls): script_path = os.path.abspath(__file__) @@ -30,17 +65,342 @@ def check_path(self, tool_calls): continue return tool_calls + def build_system_instruction(self): + prefix = "".join( + [ + "".join(self.config["description"]) + ] + ) + + plan_instruction = "".join( + [ + f'You are given the available tools from the tool list: {json.dumps(self.tool_info)} to help you solve problems. ', + 'Generate a plan with comprehensive yet minimal steps to fulfill the task. ', + 'The plan must follow the json format as below: ', + '[', + '{"message": "message_value1","tool_use": [tool_name1, tool_name2,...]}', + '{"message": "message_value2", "tool_use": [tool_name1, tool_name2,...]}', + '...', + ']', + 'In each step of the planned plan, identify tools to use and recognize no tool is necessary. ', + 'Followings are some plan examples. ', + '[' + '[', + '{"message": "gather information from arxiv. ", "tool_use": ["arxiv"]},', + '{"message", "write a summarization based on the gathered information. ", "tool_use": []}', + '];', + '[', + '{"message": "gather information from arxiv. ", "tool_use": ["arxiv"]},', + '{"message", "understand the current methods and propose ideas that can improve ", "tool_use": []}', + ']', + ']' + ] + ) + + if self.workflow_mode == "manual": + self.messages.append( + {"role": "system", "content": prefix} + ) + + else: + assert self.workflow_mode == "automatic" + self.messages.append( + {"role": "system", "content": prefix} + ) + self.messages.append( + {"role": "user", "content": plan_instruction} + ) + + def automatic_workflow(self): + for i in range(self.plan_max_fail_times): + response, start_times, end_times, waiting_times, turnaround_times = send_request( + agent_name = self.agent_name, + query=Query( + messages=self.messages, tools=None, message_return_type="json" + ) + ) + + if self.rounds == 0: + self.set_start_time(start_times[0]) + + self.request_waiting_times.extend(waiting_times) + self.request_turnaround_times.extend(turnaround_times) + + workflow = self.check_workflow(response.response_message) + + self.rounds += 1 + + if workflow: + return workflow + + else: + self.messages.append( + { + "role": "assistant", + "content": f"Fail {i+1} times to generate a valid plan. I need to regenerate a plan", + } + ) + return None + def manual_workflow(self): workflow = [ - # {"message": "Gather research topic and keywords", "tool_use": []}, - {"message": "Search for relevant papers on arXiv", "tool_use": ["arxiv"]}, - {"message": "Provide responses based on the user's query", "tool_use": []}, - # { - # "message": "Identify research gaps and generate potential research questions", - # "tool_use": [], - # }, + { + "action_type": "message_llm", + "action": "Search for relevant papers", + "tool_use": ["arxiv"], + }, + { + "action_type": "message_llm", + "action": "Provide responses based on the user's query", + "tool_use": [], + } ] return workflow + def call_tools(self, tool_calls): + # self.logger.log(f"***** It starts to call external tools *****\n", level="info") + success = True + actions = [] + observations = [] + + # print(tool_calls) + for tool_call in tool_calls: + # print(tool_call) + function_name = tool_call["name"] + function_to_call = self.tool_list[function_name] + function_params = tool_call["parameters"] + + try: + function_response = function_to_call.run(function_params) + actions.append(f"I will call the {function_name} with the params as {function_params}") + observations.append(f"The output of calling the {function_name} tool is: {function_response}") + + except Exception: + actions.append("I fail to call any tools.") + observations.append(f"The tool parameter {function_params} is invalid.") + success = False + + return actions, observations, success + def run(self): - return super().run() + self.build_system_instruction() + + task_input = self.task_input + + self.messages.append({"role": "user", "content": task_input}) + self.logger.log(f"{task_input}\n", level="info") + + workflow = None + + if self.workflow_mode == "automatic": + workflow = self.automatic_workflow() + else: + assert self.workflow_mode == "manual" + workflow = self.manual_workflow() + + self.messages = self.messages[:1] # clear long context + + self.messages.append( + { + "role": "user", + "content": f"[Thinking]: The workflow generated for the problem is {json.dumps(workflow)}. Follow the workflow to solve the problem step by step. ", + } + ) + + # if workflow: + # self.logger.log(f"Generated workflow is: {workflow}\n", level="info") + # else: + # self.logger.log( + # "Fail to generate a valid workflow. Invalid JSON?\n", level="info" + # ) + + try: + if workflow: + final_result = "" + + for i, step in enumerate(workflow): + action_type = step["action_type"] + action = step["action"] + tool_use = step["tool_use"] + + prompt = f"At step {i + 1}, you need to: {action}. " + self.messages.append({"role": "user", "content": prompt}) + + if tool_use: + selected_tools = self.pre_select_tools(tool_use) + + else: + selected_tools = None + + ( + response, + start_times, + end_times, + waiting_times, + turnaround_times, + ) = send_request( + agent_name=self.agent_name, + query=Query( + messages=self.messages, + tools=selected_tools, + action_type=action_type, + ) + ) + + if self.rounds == 0: + self.set_start_time(start_times[0]) + + # execute action + response_message = response.response_message + + tool_calls = response.tool_calls + + self.request_waiting_times.extend(waiting_times) + self.request_turnaround_times.extend(turnaround_times) + + if tool_calls: + for _ in range(self.plan_max_fail_times): + tool_calls = self.check_path(tool_calls) + actions, observations, success = self.call_tools( + tool_calls=tool_calls + ) + + action_messages = "[Action]: " + ";".join(actions) + observation_messages = "[Observation]: " + ";".join( + observations + ) + + self.messages.append( + { + "role": "assistant", + "content": action_messages + + ". " + + observation_messages, + } + ) + if success: + break + else: + thinkings = response_message + self.messages.append( + {"role": "assistant", "content": thinkings} + ) + + if i == len(workflow) - 1: + final_result = self.messages[-1] + + step_result = self.messages[-1]["content"] + self.logger.log(f"At step {i + 1}, {step_result}\n", level="info") + + self.rounds += 1 + + self.set_status("done") + self.set_end_time(time=time.time()) + + return { + "agent_name": self.agent_name, + "result": final_result, + "rounds": self.rounds, + "agent_waiting_time": self.start_time - self.created_time, + "agent_turnaround_time": self.end_time - self.created_time, + "request_waiting_times": self.request_waiting_times, + "request_turnaround_times": self.request_turnaround_times, + } + + else: + return { + "agent_name": self.agent_name, + "result": "Failed to generate a valid workflow in the given times.", + "rounds": self.rounds, + "agent_waiting_time": None, + "agent_turnaround_time": None, + "request_waiting_times": self.request_waiting_times, + "request_turnaround_times": self.request_turnaround_times, + } + except Exception as e: + print(e) + return {} + + def snake_to_camel(self, snake_str): + components = snake_str.split("_") + return "".join(x.title() for x in components) + + def load_tools(self, tool_names): + if tool_names == "None": + return + + for tool_name in tool_names: + org, name = tool_name.split("/") + module_name = ".".join(["pyopenagi", "tools", org, name]) + class_name = self.snake_to_camel(name) + + tool_module = importlib.import_module(module_name) + tool_class = getattr(tool_module, class_name) + + self.tool_list[name] = tool_class() + tool_format = tool_class().get_tool_call_format() + self.tools.append(tool_format) + self.tool_info.append( + { + "name": tool_format["function"]["name"], + "description": tool_format["function"]["description"], + } + ) + + def pre_select_tools(self, tool_names): + pre_selected_tools = [] + for tool_name in tool_names: + for tool in self.tools: + if tool["function"]["name"] == tool_name: + pre_selected_tools.append(tool) + break + + return pre_selected_tools + + def setup_logger(self): + logger = AgentLogger(self.agent_name, self.log_mode) + return logger + + def load_config(self): + script_path = os.path.abspath(__file__) + script_dir = os.path.dirname(script_path) + config_file = os.path.join(script_dir, "config.json") + with open(config_file, "r") as f: + config = json.load(f) + return config + + def set_aid(self, aid): + self.aid = aid + + def get_aid(self): + return self.aid + + def get_agent_name(self): + return self.agent_name + + def set_status(self, status): + """ + Status type: Waiting, Running, Done, Inactive + """ + self.status = status + + def get_status(self): + return self.status + + def set_created_time(self, time): + self.created_time = time + + def get_created_time(self): + return self.created_time + + def set_start_time(self, time): + self.start_time = time + + def get_start_time(self): + return self.start_time + + def set_end_time(self, time): + self.end_time = time + + def get_end_time(self): + return self.end_time \ No newline at end of file diff --git a/pyopenagi/agents/example/academic_agent/config.json b/pyopenagi/agents/example/academic_agent/config.json index 879b5ac3e..372dba829 100644 --- a/pyopenagi/agents/example/academic_agent/config.json +++ b/pyopenagi/agents/example/academic_agent/config.json @@ -9,7 +9,7 @@ ], "meta": { "author": "example", - "version": "0.0.3", + "version": "0.0.1", "license": "CC0" }, "build": { diff --git a/pyopenagi/agents/react_agent.py b/pyopenagi/agents/react_agent.py index 79fc5d53d..78e1a931f 100644 --- a/pyopenagi/agents/react_agent.py +++ b/pyopenagi/agents/react_agent.py @@ -7,18 +7,20 @@ import json +from aios.hooks.request import send_request + class ReactAgent(BaseAgent): def __init__(self, agent_name, task_input, - agent_process_factory, + # agent_process_factory, log_mode: str ): BaseAgent.__init__( self, agent_name, task_input, - agent_process_factory, + # agent_process_factory, log_mode ) @@ -35,7 +37,7 @@ def build_system_instruction(self): plan_instruction = "".join( [ f'You are given the available tools from the tool list: {json.dumps(self.tool_info)} to help you solve problems. ', - 'Generate a plan of steps you need to take. ', + 'Generate a plan with comprehensive yet minimal steps to fulfill the task. ', 'The plan must follow the json format as below: ', '[', '{"message": "message_value1","tool_use": [tool_name1, tool_name2,...]}', @@ -65,7 +67,10 @@ def build_system_instruction(self): else: assert self.workflow_mode == "automatic" self.messages.append( - {"role": "system", "content": prefix + plan_instruction} + {"role": "system", "content": prefix} + ) + self.messages.append( + {"role": "user", "content": plan_instruction} ) @@ -75,154 +80,5 @@ def automatic_workflow(self): def manual_workflow(self): pass - def call_tools(self, tool_calls): - # self.logger.log(f"***** It starts to call external tools *****\n", level="info") - success = True - actions = [] - observations = [] - - # print(tool_calls) - for tool_call in tool_calls: - # print(tool_call) - function_name = tool_call["name"] - function_to_call = self.tool_list[function_name] - function_params = tool_call["parameters"] - - try: - function_response = function_to_call.run(function_params) - actions.append(f"I will call the {function_name} with the params as {function_params}") - observations.append(f"The output of calling the {function_name} tool is: {function_response}") - - except Exception: - actions.append("I fail to call any tools.") - observations.append(f"The tool parameter {function_params} is invalid.") - success = False - - return actions, observations, success - def run(self): super().run() - self.build_system_instruction() - - task_input = self.task_input - - self.messages.append( - {"role": "user", "content": task_input} - ) - self.logger.log(f"{task_input}\n", level="info") - - workflow = None - - if self.workflow_mode == "automatic": - workflow = self.automatic_workflow() - else: - assert self.workflow_mode == "manual" - workflow = self.manual_workflow() - - self.messages.append( - {"role": "assistant", "content": f"[Thinking]: The workflow generated for the problem is {json.dumps(workflow)}"} - ) - - self.messages.append( - {"role": "user", "content": "[Thinking]: Follow the workflow to solve the problem step by step. "} - ) - - if workflow: - self.logger.log(f"Generated workflow is: {workflow}\n", level="info") - else: - self.logger.log("Fail to generate a valid workflow. Invalid JSON?\n", level="info") - - try: - if workflow: - final_result = "" - - for i, step in enumerate(workflow): - message = step["message"] - tool_use = step["tool_use"] - - prompt = f"At step {i + 1}, you need to: {message}. Outputs should be pure text without any json object" - self.messages.append({ - "role": "user", - "content": prompt - }) - if tool_use: - selected_tools = self.pre_select_tools(tool_use) - - else: - selected_tools = None - - response, start_times, end_times, waiting_times, turnaround_times = self.get_response( - query = Query( - messages = self.messages, - tools = selected_tools - ) - ) - - if self.rounds == 0: - self.set_start_time(start_times[0]) - - # execute action - response_message = response.response_message - - tool_calls = response.tool_calls - - self.request_waiting_times.extend(waiting_times) - self.request_turnaround_times.extend(turnaround_times) - - if tool_calls: - for _ in range(self.plan_max_fail_times): - tool_calls = self.check_path(tool_calls) - actions, observations, success = self.call_tools(tool_calls=tool_calls) - - action_messages = "[Action]: " + ";".join(actions) - observation_messages = "[Observation]: " + ";".join(observations) - - self.messages.append( - { - "role": "assistant", - "content": action_messages + ". " + observation_messages - } - ) - if success: - break - else: - thinkings = response_message - self.messages.append({ - "role": "assistant", - "content": thinkings - }) - - if i == len(workflow) - 1: - final_result = self.messages[-1] - - step_result = self.messages[-1]["content"] - self.logger.log(f"At step {i + 1}, {step_result}\n", level="info") - - self.rounds += 1 - - self.set_status("done") - self.set_end_time(time=time.time()) - - return { - "agent_name": self.agent_name, - "result": final_result, - "rounds": self.rounds, - "agent_waiting_time": self.start_time - self.created_time, - "agent_turnaround_time": self.end_time - self.created_time, - "request_waiting_times": self.request_waiting_times, - "request_turnaround_times": self.request_turnaround_times, - } - - else: - return { - "agent_name": self.agent_name, - "result": "Failed to generate a valid workflow in the given times.", - "rounds": self.rounds, - "agent_waiting_time": None, - "agent_turnaround_time": None, - "request_waiting_times": self.request_waiting_times, - "request_turnaround_times": self.request_turnaround_times, - } - except Exception as e: - print(e) - return {} From e3fd7537efae8936f25d82a5f66d397b9973d2f8 Mon Sep 17 00:00:00 2001 From: dongyuanjushi Date: Mon, 7 Oct 2024 21:23:34 -0400 Subject: [PATCH 04/41] update agents --- aios/scheduler/fifo_scheduler.py | 6 +++--- launch.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/aios/scheduler/fifo_scheduler.py b/aios/scheduler/fifo_scheduler.py index deabb15b5..2dd233f67 100644 --- a/aios/scheduler/fifo_scheduler.py +++ b/aios/scheduler/fifo_scheduler.py @@ -43,9 +43,9 @@ def run(self): def execute_request(self, agent_request): action_type = agent_request.query.action_type - response = self.llm.address_request(agent_request) - - if action_type == "message_llm": + if action_type in ["message_llm", "call_tool"]: + response = self.llm.address_request(agent_request) + # print(response) agent_request.set_response(response) # self.llm.address_request(agent_request) diff --git a/launch.py b/launch.py index 496d0cd5f..3f6aa63ff 100644 --- a/launch.py +++ b/launch.py @@ -49,7 +49,7 @@ def stop_server(): def run_npm(open: bool=False): # Change directory to the 'web' subdirectory - os.chdir('web') + os.chdir('agenthub') # Run npm run dev asynchronously if "node_modules" not in os.listdir(): From 8242dfe6f6bfa8f854a059c36e92bc4b5dfa26aa Mon Sep 17 00:00:00 2001 From: dongyuanjushi Date: Tue, 8 Oct 2024 08:03:44 -0400 Subject: [PATCH 05/41] update test files --- tests/test_agent_creation.py | 15 --------------- tests/test_tools/__init__.py | 0 2 files changed, 15 deletions(-) delete mode 100644 tests/test_agent_creation.py create mode 100644 tests/test_tools/__init__.py diff --git a/tests/test_agent_creation.py b/tests/test_agent_creation.py deleted file mode 100644 index ca42f7148..000000000 --- a/tests/test_agent_creation.py +++ /dev/null @@ -1,15 +0,0 @@ -from pyopenagi.agents.agent_process import AgentProcess -from pyopenagi.utils.chat_template import Query - -def test_agent_creation(): - agent_process = AgentProcess( - agent_name="example/academic_agent", - query=Query( - messages = [ - {"role": "user", "content": "Summarize researches of quantum computing in recent five years."} - ] - ) - ) - # Use plain assert statements for testing conditions - assert agent_process.agent_name == "example/academic_agent", "Agent name does not match" - # Add more assertions here as necessary to validate the properties of the agent_process object diff --git a/tests/test_tools/__init__.py b/tests/test_tools/__init__.py new file mode 100644 index 000000000..e69de29bb From 9dcda373483fae316b8318f04318285d1252caf4 Mon Sep 17 00:00:00 2001 From: dongyuanjushi Date: Tue, 8 Oct 2024 22:59:30 -0400 Subject: [PATCH 06/41] update response listener with event singal --- aios/hooks/request.py | 9 +++------ aios/scheduler/fifo_scheduler.py | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/aios/hooks/request.py b/aios/hooks/request.py index 19e964a8a..afbd4ccf1 100755 --- a/aios/hooks/request.py +++ b/aios/hooks/request.py @@ -1,4 +1,4 @@ -from threading import Thread, Lock +from threading import Thread, Lock, Event from typing import Mapping import random @@ -17,6 +17,7 @@ def __init__(self, agent_name, query): super().__init__(name=agent_name) self.agent_name = agent_name self.query = query + self.event = Event() self.pid: int = None self.status = None self.response = None @@ -89,11 +90,7 @@ def run(self): str: LLM response of Agent Process """ self.set_pid(self.native_id) - while self.get_response() is None: - time.sleep(0.1) - - return self.get_response() - + self.event.wait() class LLMRequest(AgentRequest): pass diff --git a/aios/scheduler/fifo_scheduler.py b/aios/scheduler/fifo_scheduler.py index 2dd233f67..a279a0de9 100644 --- a/aios/scheduler/fifo_scheduler.py +++ b/aios/scheduler/fifo_scheduler.py @@ -54,6 +54,6 @@ def execute_request(self, agent_request): # api_calls = self.lsfs_parser.parse(agent_request) # response = self.lsfs.execute_calls(api_calls) # agent_request.set_response(response) - + agent_request.event.set() agent_request.set_status("done") agent_request.set_end_time(time.time()) From 46f79d61f20ca91a8078a04d20ee2e54bbc8f225 Mon Sep 17 00:00:00 2001 From: dongyuanjushi Date: Fri, 11 Oct 2024 08:52:49 -0400 Subject: [PATCH 07/41] add linux installer --- installer/linux-installer.sh | 65 ++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 installer/linux-installer.sh diff --git a/installer/linux-installer.sh b/installer/linux-installer.sh new file mode 100644 index 000000000..25c6461e7 --- /dev/null +++ b/installer/linux-installer.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +# 1. Clone the GitHub repository +echo "Cloning the AIOS..." +git clone https://github.com/agiresearch/AIOS.git +cd repository || exit + +# 2. Create a new environment and install dependencies +echo "Creating a virtual environment..." +python3 -m venv venv +source venv/bin/activate + +echo "Installing dependencies..." +pip install -r requirements.txt + +# 3. Set up API keys interactively +echo "Setting up API keys..." + +# Check if the config file exists; if not, create one +CONFIG_FILE=".env" +if [ ! -f "$CONFIG_FILE" ]; then + touch "$CONFIG_FILE" +fi + +# Ask the user for API keys interactively and store them +save_api_key() { + local key_name="$1" + local user_input="$2" + + if [ -n "$user_input" ]; then + echo "$key_name=$user_input" >> "$CONFIG_FILE" + echo "$key_name has been saved." + else + echo "$key_name was skipped." + fi +} + +# Ask the user for API keys interactively and allow pressing Enter to skip +read -p "Enter your OPENAI API key for using openai models (or press Enter to skip): " OPENAI_API_KEY +save_api_key "OPENAI_API_KEY" "$OPENAI_API_KEY" + +read -p "Enter your Huggingface token for using open-sourced models (or press Enter to skip): " HF_AUTH_TOKENS +save_api_key "HF_AUTH_TOKENS" "$HF_AUTH_TOKENS" + +# Notify the user where keys are stored +echo "Installation complete. Your API keys are saved in $CONFIG_FILE if provided." + +# 4. Exit the script, leaving the environment active +echo "Activate your environment with: source venv/bin/activate" +Explanation of Changes: +Function to Save API Keys: The save_api_key function is used to store API keys only if the user enters a value. If the input is empty (i.e., the user pressed "Enter"), the key is skipped. + +bash +复制代码 +save_api_key() { + local key_name="$1" + local user_input="$2" + + if [ -n "$user_input" ]; then + echo "$key_name=$user_input" >> "$CONFIG_FILE" + echo "$key_name has been saved." + else + echo "$key_name was skipped." + fi +} \ No newline at end of file From 22828c6da1d1bf9f53b8655e37b9a3790559cfe6 Mon Sep 17 00:00:00 2001 From: 2020-qqtcg Date: Sat, 12 Oct 2024 21:30:18 +0800 Subject: [PATCH 08/41] feat: standard agent --- .../agents/experiment/standard/__init__.py | 0 .../experiment/standard/action/__init__.py | 0 .../experiment/standard/action/action.py | 8 ++ pyopenagi/agents/experiment/standard/agent.py | 100 ++++++++++++++++++ .../standard/communication/__init__.py | 0 .../agents/experiment/standard/config.json | 0 .../experiment/standard/memory/__init__.py | 0 .../standard/memory/short_term_memory.py | 20 ++++ .../experiment/standard/planning/__init__.py | 0 .../experiment/standard/planning/planning.py | 17 +++ 10 files changed, 145 insertions(+) create mode 100644 pyopenagi/agents/experiment/standard/__init__.py create mode 100644 pyopenagi/agents/experiment/standard/action/__init__.py create mode 100644 pyopenagi/agents/experiment/standard/action/action.py create mode 100644 pyopenagi/agents/experiment/standard/agent.py create mode 100644 pyopenagi/agents/experiment/standard/communication/__init__.py create mode 100644 pyopenagi/agents/experiment/standard/config.json create mode 100644 pyopenagi/agents/experiment/standard/memory/__init__.py create mode 100644 pyopenagi/agents/experiment/standard/memory/short_term_memory.py create mode 100644 pyopenagi/agents/experiment/standard/planning/__init__.py create mode 100644 pyopenagi/agents/experiment/standard/planning/planning.py diff --git a/pyopenagi/agents/experiment/standard/__init__.py b/pyopenagi/agents/experiment/standard/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyopenagi/agents/experiment/standard/action/__init__.py b/pyopenagi/agents/experiment/standard/action/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyopenagi/agents/experiment/standard/action/action.py b/pyopenagi/agents/experiment/standard/action/action.py new file mode 100644 index 000000000..257584272 --- /dev/null +++ b/pyopenagi/agents/experiment/standard/action/action.py @@ -0,0 +1,8 @@ +from abc import ABC, abstractmethod + + +class Action(ABC): + + @abstractmethod + def __call__(self, *args, **kwargs): + pass diff --git a/pyopenagi/agents/experiment/standard/agent.py b/pyopenagi/agents/experiment/standard/agent.py new file mode 100644 index 000000000..8e3c9e002 --- /dev/null +++ b/pyopenagi/agents/experiment/standard/agent.py @@ -0,0 +1,100 @@ +import time +from typing import List + +from aios.hooks.request import send_request +from pyopenagi.agents.experiment.standard.memory.short_term_memory import ShortTermMemory +from pyopenagi.agents.experiment.standard.planning.planning import Planning, DefaultPlanning +from pyopenagi.utils.chat_template import Query, Response +from pyopenagi.utils.logger import AgentLogger + + +class StandardAgent: + + def __init__(self, agent_name: str, task_input: str, log_mode: str): + # Init module + self.planning: Planning | None = None + self.actions = None + self.communication = None + self.memory = None + self.short_term_memory = ShortTermMemory() + + # Init agent base info + self.agent_name = agent_name + self.task_input = task_input + + # Init logger + self.logger = AgentLogger(agent_name, log_mode) + + # Init AIOS monitor info + self.rounds = 0 + self.status = "active" + self.start_time = None + self.end_time = None + self.request_waiting_times: list = [] + self.request_turnaround_times: list = [] + self.created_time = time.time() + + @property + def messages(self): + return self.short_term_memory.messages + + def system_prompt(self) -> str: + return """You are a smart agent.""" + + def init_module(self): + return + + def init_planning(self, planning): + self.planning = planning + + def init_communication(self, communication): + return + + def init_memory(self, memory): + return + + def init_actions(self, actions): + return + + def planning(self) -> dict: + # Select suitable messages + messages = self.short_term_memory.recall() + + planning = DefaultPlanning() + result = planning(messages, self.tools) + + return result + + def run(self): + # Init system prompt and task + self.short_term_memory.remember("system", self.system_prompt()) + self.short_term_memory.remember("user", self.task_input) + + # Run planning + # planning_result = self.planning() + + def request(self, messages: List, tools: List) -> Response: + ( + response, + start_times, + end_times, + waiting_times, + turnaround_times + ) = send_request( + agent_name=self.agent_name, + query=Query( + messages=messages, + tools=tools, + action_type="message_llm", + ) + ) + + # Update AIOS monitor info + if self.rounds == 0: + self.start_time = start_times[0] + + self.request_waiting_times.extend(waiting_times) + self.request_turnaround_times.extend(turnaround_times) + self.rounds += 1 + + return response diff --git a/pyopenagi/agents/experiment/standard/communication/__init__.py b/pyopenagi/agents/experiment/standard/communication/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyopenagi/agents/experiment/standard/config.json b/pyopenagi/agents/experiment/standard/config.json new file mode 100644 index 000000000..e69de29bb diff --git a/pyopenagi/agents/experiment/standard/memory/__init__.py b/pyopenagi/agents/experiment/standard/memory/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyopenagi/agents/experiment/standard/memory/short_term_memory.py b/pyopenagi/agents/experiment/standard/memory/short_term_memory.py new file mode 100644 index 000000000..745aa3c79 --- /dev/null +++ b/pyopenagi/agents/experiment/standard/memory/short_term_memory.py @@ -0,0 +1,20 @@ +from typing import List +from pydantic.v1 import BaseModel + + +class ShortTermMemory(BaseModel): + messages: List = [] + + def remember(self, role: str, content: str, tool_call_id: int = None) -> None: + if tool_call_id: + message = {"role": role, "content": content, "tool_call_id": tool_call_id} + self.messages += message + else: + message = {"role": role, "content": content} + self.messages += message + + def recall(self): + return self.messages + + def clear(self) -> None: + self.messages = [] diff --git a/pyopenagi/agents/experiment/standard/planning/__init__.py b/pyopenagi/agents/experiment/standard/planning/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyopenagi/agents/experiment/standard/planning/planning.py b/pyopenagi/agents/experiment/standard/planning/planning.py new file mode 100644 index 000000000..a699438fb --- /dev/null +++ b/pyopenagi/agents/experiment/standard/planning/planning.py @@ -0,0 +1,17 @@ +from abc import ABC, abstractmethod +from typing import List, Callable + +from pyopenagi.utils.chat_template import Response + + +class Planning(ABC): + + @abstractmethod + def __call__(self, *args, **kwargs): + pass + + +class DefaultPlanning(Planning): + + def __call__(self, messages: List, tools: List, request_func: Callable[[List, List], Response]): + return From 17d01f18b8aaa294d8c7cd50eedd3c19d955b265 Mon Sep 17 00:00:00 2001 From: dongyuanjushi Date: Mon, 14 Oct 2024 08:27:54 -0400 Subject: [PATCH 09/41] feat: add installer and update docs --- docs/source/agent_user/agent_user_index.rst | 4 -- docs/source/agenthub_developer/quickstart.rst | 4 -- .../aios_developer/llm_core/llm_index.rst | 6 +-- docs/source/aios_user/aios_user_index.rst | 4 -- docs/source/api_references/index.rst | 4 ++ .../installation.rst | 0 .../{aios_user => get_started}/quickstart.rst | 6 ++- docs/source/index.rst | 30 +++++------- installer/unix-like-installer.sh | 46 ++++++++++++++++++ installer/windows-installer.ps1 | 47 +++++++++++++++++++ server.py | 34 +++++++------- 11 files changed, 134 insertions(+), 51 deletions(-) delete mode 100644 docs/source/agent_user/agent_user_index.rst delete mode 100644 docs/source/agenthub_developer/quickstart.rst delete mode 100644 docs/source/aios_user/aios_user_index.rst create mode 100644 docs/source/api_references/index.rst rename docs/source/{aios_user => get_started}/installation.rst (100%) rename docs/source/{aios_user => get_started}/quickstart.rst (94%) create mode 100644 installer/unix-like-installer.sh create mode 100644 installer/windows-installer.ps1 diff --git a/docs/source/agent_user/agent_user_index.rst b/docs/source/agent_user/agent_user_index.rst deleted file mode 100644 index f1baf98dc..000000000 --- a/docs/source/agent_user/agent_user_index.rst +++ /dev/null @@ -1,4 +0,0 @@ -.. _agent_user: - -How to use agents -================= \ No newline at end of file diff --git a/docs/source/agenthub_developer/quickstart.rst b/docs/source/agenthub_developer/quickstart.rst deleted file mode 100644 index 2df364951..000000000 --- a/docs/source/agenthub_developer/quickstart.rst +++ /dev/null @@ -1,4 +0,0 @@ -.. _agenthub_quickstart: - -Quickstart -========== diff --git a/docs/source/aios_developer/llm_core/llm_index.rst b/docs/source/aios_developer/llm_core/llm_index.rst index 2e6085ad9..c7018db60 100644 --- a/docs/source/aios_developer/llm_core/llm_index.rst +++ b/docs/source/aios_developer/llm_core/llm_index.rst @@ -1,7 +1,7 @@ .. _llm_index: -LLM Classes -=========== +LLM Cores +========= LLM --- @@ -17,7 +17,7 @@ BaseLLM .. toctree:: :maxdepth: 2 - :caption: Supported LLMs + :caption: Supported LLMs as AIOS cores gpt_llm gemini_llm diff --git a/docs/source/aios_user/aios_user_index.rst b/docs/source/aios_user/aios_user_index.rst deleted file mode 100644 index 8b13a43bf..000000000 --- a/docs/source/aios_user/aios_user_index.rst +++ /dev/null @@ -1,4 +0,0 @@ -.. _aios_user: - -For AIOS User -============== diff --git a/docs/source/api_references/index.rst b/docs/source/api_references/index.rst new file mode 100644 index 000000000..7b7a585c4 --- /dev/null +++ b/docs/source/api_references/index.rst @@ -0,0 +1,4 @@ +.. _api_references: + +API References +============== \ No newline at end of file diff --git a/docs/source/aios_user/installation.rst b/docs/source/get_started/installation.rst similarity index 100% rename from docs/source/aios_user/installation.rst rename to docs/source/get_started/installation.rst diff --git a/docs/source/aios_user/quickstart.rst b/docs/source/get_started/quickstart.rst similarity index 94% rename from docs/source/aios_user/quickstart.rst rename to docs/source/get_started/quickstart.rst index d07ca0b22..4822e70ac 100644 --- a/docs/source/aios_user/quickstart.rst +++ b/docs/source/get_started/quickstart.rst @@ -7,8 +7,8 @@ Be sure to complete the :ref:`installation instructions ` bef .. tip:: For the config of LLM endpoints, multiple API keys may be required to set up. - Here we provide the .env.example for easier configuration of these API keys, - you can just copy .env.example as .env and set up the required keys based on your needs. + Here we provide the easier way to set up API API keys, + you can create the .env file and set up the required keys and add new keys based on your needs. .. code-block:: python @@ -17,6 +17,8 @@ Be sure to complete the :ref:`installation instructions ` bef HF_HOME='' HF_AUTH_TOKENS='' +Before starting the AIOS, you also need to set up the configurations in the aios_config.json file + Use with OpenAI API ------------------- diff --git a/docs/source/index.rst b/docs/source/index.rst index d5339aee7..d3fba7d18 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -25,19 +25,11 @@ Documentation .. toctree:: - :maxdepth: 2 - :caption: For AIOS Users - - aios_user/aios_user_index - aios_user/installation - aios_user/quickstart + :maxdepth: 1 + :caption: Get Started -.. toctree:: - :maxdepth: 2 - :caption: For AIOS Developers - - aios_developer/aios_developer_index - aios_developer/llm_core/llm_index + get_started/installation + get_started/quickstart .. toctree:: :maxdepth: 2 @@ -48,13 +40,15 @@ Documentation .. toctree:: :maxdepth: 2 - :caption: For Agent Users - - agent_user/agent_user_index + :caption: For AIOS Developers + aios_developer/aios_developer_index + aios_developer/llm_core/llm_index .. toctree:: - :maxdepth: 2 - :caption: For Agenthub Developers + :maxdepth: 1 + :caption: API References + + api_references/index + - agenthub_developer/quickstart diff --git a/installer/unix-like-installer.sh b/installer/unix-like-installer.sh new file mode 100644 index 000000000..9a6eb7ac9 --- /dev/null +++ b/installer/unix-like-installer.sh @@ -0,0 +1,46 @@ +#!/bin/bash +echo "Cloning the AIOS..." +git clone https://github.com/agiresearch/AIOS.git +cd AIOS || exit + +echo "Creating a virtual environment..." +python3 -m venv venv +source venv/bin/activate + +echo "Installing dependencies..." +pip install -r requirements.txt + +echo "Setting up API keys..." + +CONFIG_FILE=".env" +if [ ! -f "$CONFIG_FILE" ]; then + touch "$CONFIG_FILE" +fi + +save_api_key() { + local key_name="$1" + local user_input="$2" + + if [ -n "$user_input" ]; then + echo "$key_name=$user_input" >> "$CONFIG_FILE" + echo "$key_name has been saved." + else + echo "$key_name was skipped." + fi +} + +read -p "Enter your OPENAI API key for using openai models (or press Enter to skip): " OPENAI_API_KEY +save_api_key "OPENAI_API_KEY" "$OPENAI_API_KEY" + +read -p "Enter your GEMINI API key for using openai models (or press Enter to skip): " GEMINI_API_KEY +save_api_key "GEMINI_API_KEY" "$GEMINI_API_KEY" + +read -p "Enter your Huggingface token for using open-sourced models (or press Enter to skip): " HF_AUTH_TOKENS +save_api_key "HF_AUTH_TOKENS" "$HF_AUTH_TOKENS" + +read -p "Enter the directory you would like to store huggingface models: " HF_HOME +save_api_key "HF_HOME" "$HF_HOME" + +echo "Installation complete. Your API keys are saved in $CONFIG_FILE where you can also update the API keys later. " + +echo "You need to then customize your aios_config.json to set up configurations. After that, you can run launch.py to start your AIOS web UI locally. " diff --git a/installer/windows-installer.ps1 b/installer/windows-installer.ps1 new file mode 100644 index 000000000..08d63c604 --- /dev/null +++ b/installer/windows-installer.ps1 @@ -0,0 +1,47 @@ +Write-Host "Cloning the AIOS..." +git clone https://github.com/agiresearch/AIOS.git +Set-Location AIOS + +Write-Host "Creating a virtual environment..." +python -m venv venv +.\venv\Scripts\Activate + +Write-Host "Installing dependencies..." +pip install -r requirements.txt + +Write-Host "Setting up API keys..." + +$CONFIG_FILE = ".env" +if (-Not (Test-Path $CONFIG_FILE)) { + New-Item -Path $CONFIG_FILE -ItemType File +} + +function Save-ApiKey { + param( + [string]$KeyName, + [string]$UserInput + ) + + if ($UserInput) { + Add-Content -Path $CONFIG_FILE -Value "$KeyName=$UserInput" + Write-Host "$KeyName has been saved." + } else { + Write-Host "$KeyName was skipped." + } +} + +$OPENAI_API_KEY = Read-Host "Enter your OPENAI API key for using OpenAI models (or press Enter to skip)" +Save-ApiKey "OPENAI_API_KEY" $OPENAI_API_KEY + +$GEMINI_API_KEY = Read-Host "Enter your GEMINI API key for using Gemini models (or press Enter to skip)" +Save-ApiKey "GEMINI_API_KEY" $GEMINI_API_KEY + +$HF_AUTH_TOKENS = Read-Host "Enter your Huggingface token for using open-sourced models (or press Enter to skip)" +Save-ApiKey "HF_AUTH_TOKENS" $HF_AUTH_TOKENS + +$HF_HOME = Read-Host "Enter the directory you would like to store Huggingface models" +Save-ApiKey "HF_HOME" $HF_HOME + +Write-Host "Installation complete. Your API keys are saved in $CONFIG_FILE where you can also update the API keys later." + +Write-Host "You need to then customize your aios_config.json to set up configurations. After that, you can run launch.py to start your AIOS web UI locally." diff --git a/server.py b/server.py index 094123c69..e7ad200dd 100644 --- a/server.py +++ b/server.py @@ -19,6 +19,8 @@ from dotenv import load_dotenv import atexit +import json + load_dotenv() app = FastAPI() @@ -36,26 +38,31 @@ getFactory, setFactory, setFactoryCallback = useGlobalState() getManager, setManager, setManagerCallback = useGlobalState() -setManager(AgentManager('https://my.aios.foundation')) +setManager(AgentManager("https://my.aios.foundation")) # parser = parse_global_args() # args = parser.parse_args() # check if the llm information was specified in args +with open("aios_config.json", "r") as f: + aios_config = json.load(f) + +# only support one llm core for now +llm_cores = aios_config["llm_cores"][0] + setLLMState( useKernel( - llm_name='gpt-4o-mini', - max_gpu_memory=None, - eval_device=None, - max_new_tokens=256, - log_mode='console', - use_backend=None + llm_name=llm_cores.get("llm_name"), + max_gpu_memory=llm_cores.get("max_gpu_memory", None), + eval_device=llm_cores.get("eval_device", None) , + max_new_tokens=llm_cores.get("max_new_tokens", 1024), + log_mode="console", + use_backend=llm_cores.get("use_backend", None), ) ) - # deploy specific # leave commented # TODO conditional check if in deployment environment @@ -130,11 +137,9 @@ async def get_all_agents(): manager: AgentManager = getManager() def transform_string(input_string: str): - return '/'.join( - input_string.split("/")[:-1] - ) + return "/".join(input_string.split("/")[:-1]) - agents = (manager.list_available_agents()) + agents = manager.list_available_agents() print(agents) agent_names = [] seen = OrderedDict() @@ -145,10 +150,7 @@ def transform_string(input_string: str): agent_names.append(transformed) # Create the final list with unique display names but original IDs - _ = [ - {"id": agents[i].get("agent"), "display": name} - for name, i in seen.items() - ] + _ = [{"id": agents[i].get("agent"), "display": name} for name, i in seen.items()] return {"agents": _} From 3c4238ccba7fcec9eedcad5b69344313ce6ba9d8 Mon Sep 17 00:00:00 2001 From: dongyuanjushi Date: Mon, 14 Oct 2024 08:36:14 -0400 Subject: [PATCH 10/41] add configuration file --- aios_config.json | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 aios_config.json diff --git a/aios_config.json b/aios_config.json new file mode 100644 index 000000000..a00d0880a --- /dev/null +++ b/aios_config.json @@ -0,0 +1,9 @@ +{ + "llm_cores": [ + { + "llm_name": "gpt-4o-mini", + "use_backend": "openai", + "max_new_tokens": 1024 + } + ] +} \ No newline at end of file From b247b09e4b2496248dba76b873b7f46571bc8613 Mon Sep 17 00:00:00 2001 From: dongyuanjushi Date: Mon, 14 Oct 2024 11:26:20 -0400 Subject: [PATCH 11/41] update installation script --- installer/linux-installer.sh | 65 -------------------------------- installer/unix-like-installer.sh | 33 +++++++++++----- installer/windows-installer.ps1 | 43 +++++++++++++-------- 3 files changed, 52 insertions(+), 89 deletions(-) delete mode 100644 installer/linux-installer.sh diff --git a/installer/linux-installer.sh b/installer/linux-installer.sh deleted file mode 100644 index 25c6461e7..000000000 --- a/installer/linux-installer.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/bash - -# 1. Clone the GitHub repository -echo "Cloning the AIOS..." -git clone https://github.com/agiresearch/AIOS.git -cd repository || exit - -# 2. Create a new environment and install dependencies -echo "Creating a virtual environment..." -python3 -m venv venv -source venv/bin/activate - -echo "Installing dependencies..." -pip install -r requirements.txt - -# 3. Set up API keys interactively -echo "Setting up API keys..." - -# Check if the config file exists; if not, create one -CONFIG_FILE=".env" -if [ ! -f "$CONFIG_FILE" ]; then - touch "$CONFIG_FILE" -fi - -# Ask the user for API keys interactively and store them -save_api_key() { - local key_name="$1" - local user_input="$2" - - if [ -n "$user_input" ]; then - echo "$key_name=$user_input" >> "$CONFIG_FILE" - echo "$key_name has been saved." - else - echo "$key_name was skipped." - fi -} - -# Ask the user for API keys interactively and allow pressing Enter to skip -read -p "Enter your OPENAI API key for using openai models (or press Enter to skip): " OPENAI_API_KEY -save_api_key "OPENAI_API_KEY" "$OPENAI_API_KEY" - -read -p "Enter your Huggingface token for using open-sourced models (or press Enter to skip): " HF_AUTH_TOKENS -save_api_key "HF_AUTH_TOKENS" "$HF_AUTH_TOKENS" - -# Notify the user where keys are stored -echo "Installation complete. Your API keys are saved in $CONFIG_FILE if provided." - -# 4. Exit the script, leaving the environment active -echo "Activate your environment with: source venv/bin/activate" -Explanation of Changes: -Function to Save API Keys: The save_api_key function is used to store API keys only if the user enters a value. If the input is empty (i.e., the user pressed "Enter"), the key is skipped. - -bash -复制代码 -save_api_key() { - local key_name="$1" - local user_input="$2" - - if [ -n "$user_input" ]; then - echo "$key_name=$user_input" >> "$CONFIG_FILE" - echo "$key_name has been saved." - else - echo "$key_name was skipped." - fi -} \ No newline at end of file diff --git a/installer/unix-like-installer.sh b/installer/unix-like-installer.sh index 9a6eb7ac9..5fc6bacc9 100644 --- a/installer/unix-like-installer.sh +++ b/installer/unix-like-installer.sh @@ -7,9 +7,6 @@ echo "Creating a virtual environment..." python3 -m venv venv source venv/bin/activate -echo "Installing dependencies..." -pip install -r requirements.txt - echo "Setting up API keys..." CONFIG_FILE=".env" @@ -29,18 +26,36 @@ save_api_key() { fi } -read -p "Enter your OPENAI API key for using openai models (or press Enter to skip): " OPENAI_API_KEY +read -p "Enter your OPENAI API key for using OpenAI models (or press Enter to skip): " OPENAI_API_KEY save_api_key "OPENAI_API_KEY" "$OPENAI_API_KEY" -read -p "Enter your GEMINI API key for using openai models (or press Enter to skip): " GEMINI_API_KEY +read -p "Enter your GEMINI API key for using OpenAI models (or press Enter to skip): " GEMINI_API_KEY save_api_key "GEMINI_API_KEY" "$GEMINI_API_KEY" read -p "Enter your Huggingface token for using open-sourced models (or press Enter to skip): " HF_AUTH_TOKENS save_api_key "HF_AUTH_TOKENS" "$HF_AUTH_TOKENS" -read -p "Enter the directory you would like to store huggingface models: " HF_HOME +read -p "Enter the directory you would like to store Huggingface models: " HF_HOME save_api_key "HF_HOME" "$HF_HOME" -echo "Installation complete. Your API keys are saved in $CONFIG_FILE where you can also update the API keys later. " - -echo "You need to then customize your aios_config.json to set up configurations. After that, you can run launch.py to start your AIOS web UI locally. " +# Prompt for GPU environment +echo "Do you have a GPU environment for running the models?" +select gpu_choice in "Yes" "No"; do + case $gpu_choice in + Yes ) + echo "Installing dependencies from requirements-cuda.txt for GPU environment..." + pip install -r requirements-cuda.txt + break + ;; + No ) + echo "Installing dependencies from requirements.txt for CPU environment..." + pip install -r requirements.txt + break + ;; + * ) echo "Please answer Yes or No.";; + esac +done + +echo "Installation complete. Your API keys are saved in $CONFIG_FILE where you can also update the API keys later." + +echo "You need to then customize your aios_config.json to set up configurations. After that, you can run launch.py to start your AIOS web UI locally." diff --git a/installer/windows-installer.ps1 b/installer/windows-installer.ps1 index 08d63c604..3e6f3be96 100644 --- a/installer/windows-installer.ps1 +++ b/installer/windows-installer.ps1 @@ -1,39 +1,38 @@ -Write-Host "Cloning the AIOS..." +# Windows PowerShell installation script for AIOS + +Write-Host "Cloning the AIOS repository..." git clone https://github.com/agiresearch/AIOS.git -Set-Location AIOS +Set-Location -Path "AIOS" Write-Host "Creating a virtual environment..." python -m venv venv .\venv\Scripts\Activate -Write-Host "Installing dependencies..." -pip install -r requirements.txt - Write-Host "Setting up API keys..." $CONFIG_FILE = ".env" if (-Not (Test-Path $CONFIG_FILE)) { - New-Item -Path $CONFIG_FILE -ItemType File + New-Item -ItemType File -Path $CONFIG_FILE } function Save-ApiKey { - param( - [string]$KeyName, - [string]$UserInput + param ( + [string]$key_name, + [string]$user_input ) - - if ($UserInput) { - Add-Content -Path $CONFIG_FILE -Value "$KeyName=$UserInput" - Write-Host "$KeyName has been saved." + + if ($user_input) { + Add-Content -Path $CONFIG_FILE -Value "$key_name=$user_input" + Write-Host "$key_name has been saved." } else { - Write-Host "$KeyName was skipped." + Write-Host "$key_name was skipped." } } $OPENAI_API_KEY = Read-Host "Enter your OPENAI API key for using OpenAI models (or press Enter to skip)" Save-ApiKey "OPENAI_API_KEY" $OPENAI_API_KEY -$GEMINI_API_KEY = Read-Host "Enter your GEMINI API key for using Gemini models (or press Enter to skip)" +$GEMINI_API_KEY = Read-Host "Enter your GEMINI API key for using OpenAI models (or press Enter to skip)" Save-ApiKey "GEMINI_API_KEY" $GEMINI_API_KEY $HF_AUTH_TOKENS = Read-Host "Enter your Huggingface token for using open-sourced models (or press Enter to skip)" @@ -42,6 +41,20 @@ Save-ApiKey "HF_AUTH_TOKENS" $HF_AUTH_TOKENS $HF_HOME = Read-Host "Enter the directory you would like to store Huggingface models" Save-ApiKey "HF_HOME" $HF_HOME +# Prompt for GPU environment +$gpu_choice = Read-Host "Do you have a GPU environment for running the models? (Yes/No)" + +if ($gpu_choice -eq "Yes") { + Write-Host "Installing dependencies from requirements-cuda.txt for GPU environment..." + pip install -r requirements-cuda.txt +} elseif ($gpu_choice -eq "No") { + Write-Host "Installing dependencies from requirements.txt for CPU environment..." + pip install -r requirements.txt +} else { + Write-Host "Invalid choice. Please run the script again and choose Yes or No." + exit +} + Write-Host "Installation complete. Your API keys are saved in $CONFIG_FILE where you can also update the API keys later." Write-Host "You need to then customize your aios_config.json to set up configurations. After that, you can run launch.py to start your AIOS web UI locally." From de19cbfc1856def2deab982cd38e7f99f4a59aa4 Mon Sep 17 00:00:00 2001 From: dongyuanjushi Date: Tue, 15 Oct 2024 15:36:49 -0400 Subject: [PATCH 12/41] update docs --- .../agent_framework/autogen.rst | 6 +- .../agent_framework/metagpt.rst | 4 +- ...eloper_index.rst => development_rules.rst} | 4 +- .../agent_developer/minimal_example.rst | 7 ++ .../aios_developer/aios_developer_index.rst | 4 - docs/source/aios_developer/scheduler/fifo.rst | 7 ++ .../scheduler/scheduler_index.rst | 10 +++ docs/source/get_started/installation.rst | 3 - docs/source/index.rst | 9 ++- installer/unix-like-installer.sh | 28 +++++-- installer/windows-installer.ps1 | 75 ++++++++++--------- 11 files changed, 97 insertions(+), 60 deletions(-) rename docs/source/agent_developer/{agent_developer_index.rst => development_rules.rst} (95%) create mode 100644 docs/source/agent_developer/minimal_example.rst delete mode 100644 docs/source/aios_developer/aios_developer_index.rst create mode 100644 docs/source/aios_developer/scheduler/fifo.rst create mode 100644 docs/source/aios_developer/scheduler/scheduler_index.rst diff --git a/docs/source/agent_developer/agent_framework/autogen.rst b/docs/source/agent_developer/agent_framework/autogen.rst index 6b7824d0f..1d1bd0589 100644 --- a/docs/source/agent_developer/agent_framework/autogen.rst +++ b/docs/source/agent_developer/agent_framework/autogen.rst @@ -1,5 +1,5 @@ -AutoGen For AIOS -================ +Use AutoGen +=========== Introduction ------------ @@ -19,7 +19,7 @@ before you create an autogen agent, and select a framework type through ``Framew use AutoGen, you should use ``FrameworkType.AutoGen``. Then create autogen agent. When running on AIOS, you don't need to supply parameter ``llm_config``, this parameter configures the llm model that the agent will use. -Because AIOS will controll the llm call. +Because AIOS will deal with the calling of llms in the backend. .. code-block:: python diff --git a/docs/source/agent_developer/agent_framework/metagpt.rst b/docs/source/agent_developer/agent_framework/metagpt.rst index 6fecbfe0b..7564988ce 100644 --- a/docs/source/agent_developer/agent_framework/metagpt.rst +++ b/docs/source/agent_developer/agent_framework/metagpt.rst @@ -1,5 +1,5 @@ -MetaGPT For AIOS -========================= +Use MetaGPT +=========== Introduction ------------ diff --git a/docs/source/agent_developer/agent_developer_index.rst b/docs/source/agent_developer/development_rules.rst similarity index 95% rename from docs/source/agent_developer/agent_developer_index.rst rename to docs/source/agent_developer/development_rules.rst index 3ce42d5d6..8cb5cdea3 100644 --- a/docs/source/agent_developer/agent_developer_index.rst +++ b/docs/source/agent_developer/development_rules.rst @@ -1,7 +1,7 @@ .. _agent_index.rst: -The standard for developing agents -================================== +Need to know before building agents +=================================== To develop a new agent to run on top of the AIOS, you need to follow rules as below. diff --git a/docs/source/agent_developer/minimal_example.rst b/docs/source/agent_developer/minimal_example.rst new file mode 100644 index 000000000..b58b3e80a --- /dev/null +++ b/docs/source/agent_developer/minimal_example.rst @@ -0,0 +1,7 @@ +.. _minimal_example.rst: + +Build your first agent +====================== + +Here are instructions of how to build your first agent + diff --git a/docs/source/aios_developer/aios_developer_index.rst b/docs/source/aios_developer/aios_developer_index.rst deleted file mode 100644 index d0d5e183a..000000000 --- a/docs/source/aios_developer/aios_developer_index.rst +++ /dev/null @@ -1,4 +0,0 @@ -.. _aios_developer: - -For AIOS Developer -================== \ No newline at end of file diff --git a/docs/source/aios_developer/scheduler/fifo.rst b/docs/source/aios_developer/scheduler/fifo.rst new file mode 100644 index 000000000..13114a5fd --- /dev/null +++ b/docs/source/aios_developer/scheduler/fifo.rst @@ -0,0 +1,7 @@ +FIFO Scheduler +============== + +Source https://github.com/agiresearch/AIOS/blob/main/aios/scheduler/fifo_scheduler.py. + +.. literalinclude:: ../../../../aios/scheduler/fifo_scheduler.py + :language: python \ No newline at end of file diff --git a/docs/source/aios_developer/scheduler/scheduler_index.rst b/docs/source/aios_developer/scheduler/scheduler_index.rst new file mode 100644 index 000000000..c2ee0b3fe --- /dev/null +++ b/docs/source/aios_developer/scheduler/scheduler_index.rst @@ -0,0 +1,10 @@ +.. _scheduler_index: + +Scheduler +========= + +.. toctree:: + :maxdepth: 2 + :caption: Scheduler + + fifo diff --git a/docs/source/get_started/installation.rst b/docs/source/get_started/installation.rst index 61bba0e16..9486746a9 100644 --- a/docs/source/get_started/installation.rst +++ b/docs/source/get_started/installation.rst @@ -4,12 +4,9 @@ Installation ============ Prerequsites ------------ -* Anaconda * Python: 3.9-3.11 * Git -.. _build_from_source: - Build from source ----------------- Git clone AIOS repository diff --git a/docs/source/index.rst b/docs/source/index.rst index d3fba7d18..2b51dccb8 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -32,18 +32,19 @@ Documentation get_started/quickstart .. toctree:: - :maxdepth: 2 + :maxdepth: 1 :caption: For Agent Developers - agent_developer/agent_developer_index + agent_developer/development_rules + agent_developer/minimal_example.rst agent_developer/agent_framework/framework_index .. toctree:: - :maxdepth: 2 + :maxdepth: 1 :caption: For AIOS Developers - aios_developer/aios_developer_index aios_developer/llm_core/llm_index + aios_developer/scheduler/scheduler_index .. toctree:: :maxdepth: 1 diff --git a/installer/unix-like-installer.sh b/installer/unix-like-installer.sh index 5fc6bacc9..b99289a71 100644 --- a/installer/unix-like-installer.sh +++ b/installer/unix-like-installer.sh @@ -1,4 +1,16 @@ #!/bin/bash + +RED='\033[0;31m' +GREEN='\033[0;32m' +BLUE='\033[0;34m' +BOLD='\033[1m' +RESET='\033[0m' + +echo -e "${BLUE}${BOLD}=====================================${RESET}" +echo -e "${GREEN}${BOLD} Welcome to AIOS Installation! ${RESET}" +echo -e "${BLUE}${BOLD}=====================================${RESET}" +echo "" + echo "Cloning the AIOS..." git clone https://github.com/agiresearch/AIOS.git cd AIOS || exit @@ -26,10 +38,12 @@ save_api_key() { fi } +echo -e "${BOLD}Please enter your API keys:${RESET}" + read -p "Enter your OPENAI API key for using OpenAI models (or press Enter to skip): " OPENAI_API_KEY save_api_key "OPENAI_API_KEY" "$OPENAI_API_KEY" -read -p "Enter your GEMINI API key for using OpenAI models (or press Enter to skip): " GEMINI_API_KEY +read -p "Enter your GEMINI API key for using GEMINI models (or press Enter to skip): " GEMINI_API_KEY save_api_key "GEMINI_API_KEY" "$GEMINI_API_KEY" read -p "Enter your Huggingface token for using open-sourced models (or press Enter to skip): " HF_AUTH_TOKENS @@ -38,8 +52,7 @@ save_api_key "HF_AUTH_TOKENS" "$HF_AUTH_TOKENS" read -p "Enter the directory you would like to store Huggingface models: " HF_HOME save_api_key "HF_HOME" "$HF_HOME" -# Prompt for GPU environment -echo "Do you have a GPU environment for running the models?" +echo -e "${BOLD}Do you have a GPU environment for running the models?${RESET}" select gpu_choice in "Yes" "No"; do case $gpu_choice in Yes ) @@ -56,6 +69,9 @@ select gpu_choice in "Yes" "No"; do esac done -echo "Installation complete. Your API keys are saved in $CONFIG_FILE where you can also update the API keys later." - -echo "You need to then customize your aios_config.json to set up configurations. After that, you can run launch.py to start your AIOS web UI locally." +# Final styled message +echo -e "${GREEN}${BOLD}============================================================${RESET}" +echo -e "${GREEN}${BOLD}Installation complete! Your API keys are saved in $CONFIG_FILE.${RESET}" +echo -e "${GREEN}${BOLD}You can also update the API keys later.${RESET}" +echo -e "${GREEN}${BOLD}Next steps: customize your aios_config.json and run launch.py.${RESET}" +echo -e "${GREEN}${BOLD}============================================================${RESET}" diff --git a/installer/windows-installer.ps1 b/installer/windows-installer.ps1 index 3e6f3be96..7400f9bc1 100644 --- a/installer/windows-installer.ps1 +++ b/installer/windows-installer.ps1 @@ -1,13 +1,36 @@ -# Windows PowerShell installation script for AIOS - -Write-Host "Cloning the AIOS repository..." +$RED = "Red" +$GREEN = "Green" +$BLUE = "Blue" +$BOLD = "" # No direct bold support, but we'll emphasize via structure +$RESET = "" # No need for reset + +# Welcome message with colors +Write-Host "=====================================" -ForegroundColor $BLUE +Write-Host " Welcome to AIOS Installation! " -ForegroundColor $GREEN +Write-Host "=====================================" -ForegroundColor $BLUE +Write-Host "" + +# Cloning the AIOS repository +Write-Host "Cloning the AIOS..." git clone https://github.com/agiresearch/AIOS.git -Set-Location -Path "AIOS" +if ($LASTEXITCODE -ne 0) { + Write-Host "Failed to clone the AIOS repository." -ForegroundColor $RED + exit 1 +} +Set-Location "AIOS" +# Creating a virtual environment Write-Host "Creating a virtual environment..." python -m venv venv -.\venv\Scripts\Activate +if ($LASTEXITCODE -ne 0) { + Write-Host "Failed to create virtual environment." -ForegroundColor $RED + exit 1 +} + +# Activating the virtual environment +& "venv\Scripts\Activate.ps1" +# Setting up API keys Write-Host "Setting up API keys..." $CONFIG_FILE = ".env" @@ -15,46 +38,26 @@ if (-Not (Test-Path $CONFIG_FILE)) { New-Item -ItemType File -Path $CONFIG_FILE } -function Save-ApiKey { +# Function to save API keys +function Save-APIKey { param ( [string]$key_name, [string]$user_input ) - - if ($user_input) { + if ($user_input -ne "") { Add-Content -Path $CONFIG_FILE -Value "$key_name=$user_input" Write-Host "$key_name has been saved." - } else { + } + else { Write-Host "$key_name was skipped." } } -$OPENAI_API_KEY = Read-Host "Enter your OPENAI API key for using OpenAI models (or press Enter to skip)" -Save-ApiKey "OPENAI_API_KEY" $OPENAI_API_KEY - -$GEMINI_API_KEY = Read-Host "Enter your GEMINI API key for using OpenAI models (or press Enter to skip)" -Save-ApiKey "GEMINI_API_KEY" $GEMINI_API_KEY +# Prompt for API keys +Write-Host "Please enter your API keys:" -$HF_AUTH_TOKENS = Read-Host "Enter your Huggingface token for using open-sourced models (or press Enter to skip)" -Save-ApiKey "HF_AUTH_TOKENS" $HF_AUTH_TOKENS - -$HF_HOME = Read-Host "Enter the directory you would like to store Huggingface models" -Save-ApiKey "HF_HOME" $HF_HOME - -# Prompt for GPU environment -$gpu_choice = Read-Host "Do you have a GPU environment for running the models? (Yes/No)" - -if ($gpu_choice -eq "Yes") { - Write-Host "Installing dependencies from requirements-cuda.txt for GPU environment..." - pip install -r requirements-cuda.txt -} elseif ($gpu_choice -eq "No") { - Write-Host "Installing dependencies from requirements.txt for CPU environment..." - pip install -r requirements.txt -} else { - Write-Host "Invalid choice. Please run the script again and choose Yes or No." - exit -} - -Write-Host "Installation complete. Your API keys are saved in $CONFIG_FILE where you can also update the API keys later." +$OPENAI_API_KEY = Read-Host "Enter your OPENAI API key for using OpenAI models (or press Enter to skip)" +Save-APIKey -key_name "OPENAI_API_KEY" -user_input $OPENAI_API_KEY -Write-Host "You need to then customize your aios_config.json to set up configurations. After that, you can run launch.py to start your AIOS web UI locally." +$GEMINI_API_KEY = Read-Host "Enter your GEMINI API key for using GEMINI models (or press Enter to skip)" +Save-APIKey -key_name "GEMINI_API_KEY" -user_input $GEM From 176776782e78d6f0d3904247b14495142e054bbf Mon Sep 17 00:00:00 2001 From: dongyuanjushi Date: Tue, 15 Oct 2024 15:40:13 -0400 Subject: [PATCH 13/41] rm unused installation script --- installer/linux-installer.sh | 65 ------------------------------------ 1 file changed, 65 deletions(-) delete mode 100644 installer/linux-installer.sh diff --git a/installer/linux-installer.sh b/installer/linux-installer.sh deleted file mode 100644 index 25c6461e7..000000000 --- a/installer/linux-installer.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/bash - -# 1. Clone the GitHub repository -echo "Cloning the AIOS..." -git clone https://github.com/agiresearch/AIOS.git -cd repository || exit - -# 2. Create a new environment and install dependencies -echo "Creating a virtual environment..." -python3 -m venv venv -source venv/bin/activate - -echo "Installing dependencies..." -pip install -r requirements.txt - -# 3. Set up API keys interactively -echo "Setting up API keys..." - -# Check if the config file exists; if not, create one -CONFIG_FILE=".env" -if [ ! -f "$CONFIG_FILE" ]; then - touch "$CONFIG_FILE" -fi - -# Ask the user for API keys interactively and store them -save_api_key() { - local key_name="$1" - local user_input="$2" - - if [ -n "$user_input" ]; then - echo "$key_name=$user_input" >> "$CONFIG_FILE" - echo "$key_name has been saved." - else - echo "$key_name was skipped." - fi -} - -# Ask the user for API keys interactively and allow pressing Enter to skip -read -p "Enter your OPENAI API key for using openai models (or press Enter to skip): " OPENAI_API_KEY -save_api_key "OPENAI_API_KEY" "$OPENAI_API_KEY" - -read -p "Enter your Huggingface token for using open-sourced models (or press Enter to skip): " HF_AUTH_TOKENS -save_api_key "HF_AUTH_TOKENS" "$HF_AUTH_TOKENS" - -# Notify the user where keys are stored -echo "Installation complete. Your API keys are saved in $CONFIG_FILE if provided." - -# 4. Exit the script, leaving the environment active -echo "Activate your environment with: source venv/bin/activate" -Explanation of Changes: -Function to Save API Keys: The save_api_key function is used to store API keys only if the user enters a value. If the input is empty (i.e., the user pressed "Enter"), the key is skipped. - -bash -复制代码 -save_api_key() { - local key_name="$1" - local user_input="$2" - - if [ -n "$user_input" ]; then - echo "$key_name=$user_input" >> "$CONFIG_FILE" - echo "$key_name has been saved." - else - echo "$key_name was skipped." - fi -} \ No newline at end of file From 201945169cf8ecae1d3fc269b4a1a9a6add6f627 Mon Sep 17 00:00:00 2001 From: dongyuanjushi Date: Thu, 17 Oct 2024 09:38:12 -0400 Subject: [PATCH 14/41] update --- aios/hooks/llm.py | 182 --------------------- aios/hooks/modules/agent.py | 78 +++++++++ aios/hooks/modules/llm.py | 65 ++++++++ aios/hooks/modules/memory.py | 42 +++++ aios/hooks/modules/scheduler.py | 82 ++++++++++ aios/hooks/request.py | 92 +++++++++-- aios/hooks/starter.py | 54 ++++++ aios/hooks/stores/_global.py | 20 ++- aios/hooks/stores/queue.py | 10 +- aios/hooks/types/agent.py | 16 ++ aios/hooks/types/llm.py | 34 +--- aios/hooks/types/memory.py | 9 + aios/hooks/types/scheduler.py | 11 ++ aios/hooks/utils/__init__.py | 0 aios/hooks/{ => utils}/parser.py | 0 aios/hooks/{ => utils}/utils.py | 0 aios/hooks/{ => utils}/validate.py | 0 aios/llm_core/llm_classes/claude_llm.py | 8 +- aios/llm_core/llm_classes/gemini_llm.py | 6 +- aios/llm_core/llm_classes/gpt_llm.py | 6 +- aios/llm_core/llm_classes/hf_native_llm.py | 6 +- aios/llm_core/llm_classes/ollama_llm.py | 6 +- aios/llm_core/llm_classes/vllm.py | 6 +- aios/scheduler/fifo_scheduler.py | 114 +++++++++---- pyopenagi/agents/agent_factory.py | 71 ++++---- 25 files changed, 600 insertions(+), 318 deletions(-) delete mode 100644 aios/hooks/llm.py create mode 100644 aios/hooks/modules/agent.py create mode 100644 aios/hooks/modules/llm.py create mode 100644 aios/hooks/modules/memory.py create mode 100644 aios/hooks/modules/scheduler.py create mode 100644 aios/hooks/starter.py create mode 100644 aios/hooks/types/agent.py create mode 100644 aios/hooks/types/memory.py create mode 100644 aios/hooks/types/scheduler.py create mode 100644 aios/hooks/utils/__init__.py rename aios/hooks/{ => utils}/parser.py (100%) rename aios/hooks/{ => utils}/utils.py (100%) rename aios/hooks/{ => utils}/validate.py (100%) diff --git a/aios/hooks/llm.py b/aios/hooks/llm.py deleted file mode 100644 index 87cfbfa91..000000000 --- a/aios/hooks/llm.py +++ /dev/null @@ -1,182 +0,0 @@ -from concurrent.futures import ThreadPoolExecutor, Future -from contextlib import contextmanager - -from typing import Any -from random import randint - -from aios.llm_core.llms import LLM - -from aios.scheduler.fifo_scheduler import FIFOScheduler - -from aios.hooks.types.llm import AgentSubmitDeclaration, FactoryParams, LLMParams, SchedulerParams, LLMRequestQueue, \ - QueueGetMessage, QueueAddMessage, QueueCheckEmpty -from aios.hooks.validate import validate - -from aios.hooks.stores import queue as QueueStore, processes as ProcessStore - -from aios.hooks.utils import generate_random_string - -from pyopenagi.agents.agent_factory import AgentFactory - -ids = [] - - -@validate(LLMParams) -def useKernel(params: LLMParams) -> LLM: - return LLM(**params.model_dump()) - - -def useLLMRequestQueue() -> tuple[LLMRequestQueue, QueueGetMessage, QueueAddMessage, QueueCheckEmpty]: - r_str = generate_random_string() - _ = LLMRequestQueue() - - QueueStore.LLM_REQUEST_QUEUE[r_str] = _ - - def getMessage(): - return QueueStore.getMessage(_) - - def addMessage(message: str): - return QueueStore.addMessage(_, message) - - def isEmpty(): - return QueueStore.isEmpty(_) - - return _, getMessage, addMessage, isEmpty - - -@validate(SchedulerParams) -def useFIFOScheduler(params: SchedulerParams): - if params.get_queue_message is None: - from aios.hooks.stores._global import global_llm_req_queue_get_message - - params.get_queue_message = global_llm_req_queue_get_message - - scheduler = FIFOScheduler(**params.model_dump()) - - def startScheduler(): - scheduler.start() - - def stopScheduler(): - scheduler.stop() - - return startScheduler, stopScheduler - - -@validate(FactoryParams) -def useFactory(params: FactoryParams): - # process_factory = AgentProcessFactory() - - agent_factory = AgentFactory( - # agent_process_factory=process_factory, - agent_log_mode=params.log_mode, - ) - - thread_pool = ThreadPoolExecutor(max_workers=params.max_workers) - - @validate(AgentSubmitDeclaration) - def submitAgent(declaration_params: AgentSubmitDeclaration) -> None: - _submitted_agent: Future = thread_pool.submit( - agent_factory.run_agent, - declaration_params.agent_name, - declaration_params.task_input - ) - # _submitted_agent = - - random_code = randint(100000, 999999) - - while random_code in ids: - random_code = randint(100000, 999999) - - ProcessStore.addProcess(_submitted_agent, random_code) - - return random_code - - # def awaitAgentExecution() -> dict[str, Any]: - # res = [] - - # for r in as_completed(ProcessStore.AGENT_PROCESSES): - # _ = r.result() - # res.append(_) - - # return res - - def awaitAgentExecution(process_id: str) -> dict[str, Any]: - future = ProcessStore.AGENT_PROCESSES.get(process_id) - - if future: - # with threading.Lock(): - # ids = [x for x in ids if x != process_id] - return future.result() - else: - raise ValueError(f"Process with ID '{process_id}' not found.") - - return submitAgent, awaitAgentExecution - - -@contextmanager -@validate(SchedulerParams) -def fifo_scheduler(params: SchedulerParams): - """ - A context manager that starts and stops a FIFO scheduler. - - Args: - params (SchedulerParams): The parameters for the scheduler. - """ - if params.get_queue_message is None: - from aios.hooks.stores._global import global_llm_req_queue_get_message - params.get_queue_message = global_llm_req_queue_get_message - - scheduler = FIFOScheduler(**params.model_dump()) - - scheduler.start() - yield - scheduler.stop() - - -@contextmanager -def aios_starter( - llm_name, - max_gpu_memory, - eval_device, - max_new_tokens, - scheduler_log_mode, - agent_log_mode, - llm_kernel_log_mode, - use_backend -): - """ - Starts a LLM kernel and a scheduler for running agents, - returning a submitAgent and awaitAgentExecution function. - - Args: - llm_name (str): The name of the LLM kernel to use. - max_gpu_memory (str): The maximum amount of GPU memory to use. - eval_device (str): The device to evaluate the LLM on. - max_new_tokens (int): The maximum number of new tokens to generate. - scheduler_log_mode (str): The log mode for the scheduler. - agent_log_mode (str): The log mode for the agents. - llm_kernel_log_mode (str): The log mode for the LLM kernel. - use_backend (str): The backend to use for running the LLM kernel. - - Yields: - submitAgent (Callable[[str, str], str]): A function that submits an agent for execution. - awaitAgentExecution (Callable[[str], dict[str, Any]]): A function that waits for an agent - to complete and returns its result. - """ - llm = useKernel( - llm_name=llm_name, - max_gpu_memory=max_gpu_memory, - eval_device=eval_device, - max_new_tokens=max_new_tokens, - log_mode=llm_kernel_log_mode, - use_backend=use_backend - ) - - # run agents concurrently for maximum efficiency using a scheduler - submit_agent, await_agent_execution = useFactory( - log_mode=agent_log_mode, - max_workers=64 - ) - - with fifo_scheduler(llm=llm, log_mode=scheduler_log_mode, get_queue_message=None): - yield submit_agent, await_agent_execution diff --git a/aios/hooks/modules/agent.py b/aios/hooks/modules/agent.py new file mode 100644 index 000000000..b7fbc414e --- /dev/null +++ b/aios/hooks/modules/agent.py @@ -0,0 +1,78 @@ +from concurrent.futures import ThreadPoolExecutor, Future +from random import randint +from typing import Any, Tuple, Callable, Dict +from aios.hooks.types.agent import AgentSubmitDeclaration, FactoryParams +from aios.hooks.utils.validate import validate +from aios.hooks.stores import queue as QueueStore, processes as ProcessStore + +# from aios.hooks.utils import generate_random_string +from pyopenagi.agents.agent_factory import AgentFactory + +ids = [] + +@validate(FactoryParams) +def useFactory( + params: FactoryParams, +) -> Tuple[Callable[[AgentSubmitDeclaration], int], Callable[[str], Dict[str, Any]]]: + """ + Initializes the agent factory and returns functions to submit agents and await their execution. + + Args: + params (FactoryParams): Parameters required to initialize the agent factory. + + Returns: + Tuple: A tuple containing the submitAgent and awaitAgentExecution functions. + """ + agent_factory = AgentFactory( + agent_log_mode=params.log_mode, + ) + + thread_pool = ThreadPoolExecutor(max_workers=params.max_workers) + + @validate(AgentSubmitDeclaration) + def submitAgent(declaration_params: AgentSubmitDeclaration) -> int: + """ + Submits an agent for execution and returns a unique process ID. + + Args: + declaration_params (AgentSubmitDeclaration): Parameters to declare the agent submission. + + Returns: + int: A unique process ID for the submitted agent. + """ + _submitted_agent: Future = thread_pool.submit( + agent_factory.run_agent, + declaration_params.agent_name, + declaration_params.task_input, + ) + + # Generate a unique process ID + random_code = randint(100000, 999999) + while random_code in ids: + random_code = randint(100000, 999999) + + ProcessStore.addProcess(_submitted_agent, random_code) + + return random_code + + def awaitAgentExecution(process_id: str) -> Dict[str, Any]: + """ + Waits for the agent execution to complete and returns the result. + + Args: + process_id (str): The ID of the process to await. + + Returns: + dict: The result of the agent execution. + + Raises: + ValueError: If the process ID is not found. + """ + future = ProcessStore.AGENT_PROCESSES.get(process_id) + + if future: + return future.result() + else: + raise ValueError(f"Process with ID '{process_id}' not found.") + + return submitAgent, awaitAgentExecution diff --git a/aios/hooks/modules/llm.py b/aios/hooks/modules/llm.py new file mode 100644 index 000000000..23c6da0cb --- /dev/null +++ b/aios/hooks/modules/llm.py @@ -0,0 +1,65 @@ +from random import randint + +from typing import Tuple + +from aios.llm_core.llms import LLM +from aios.hooks.types.llm import ( + LLMParams, + LLMRequestQueue, + LLMRequestQueueAddMessage, + LLMRequestQueueGetMessage, + LLMRequestQueueCheckEmpty +) +from aios.hooks.utils.validate import validate +from aios.hooks.stores import queue as QueueStore, processes as ProcessStore +# from aios.hooks.utils import generate_random_string +# from pyopenagi.agents.agent_factory import AgentFactory + +ids = [] # List to store process IDs + + +@validate(LLMParams) +def useKernel(params: LLMParams) -> LLM: + """ + Initialize and return a Language Learning Model (LLM) instance. + + Args: + params (LLMParams): Parameters required for LLM initialization. + + Returns: + LLM: An instance of the initialized LLM. + """ + return LLM(**params.model_dump()) + + +def useLLMRequestQueue() -> ( + Tuple[LLMRequestQueue, LLMRequestQueueGetMessage, LLMRequestQueueAddMessage, LLMRequestQueueCheckEmpty] +): + """ + Creates and returns a queue for LLM requests along with helper methods to manage the queue. + + Returns: + Tuple: A tuple containing the LLM request queue, get message function, add message function, and check queue empty function. + """ + # r_str = ( + # generate_random_string() + # ) # Generate a random string for queue identification + r_str = "llm" + _ = LLMRequestQueue() + + # Store the LLM request queue in QueueStore + QueueStore.REQUEST_QUEUE[r_str] = _ + + # Function to get messages from the queue + def getMessage(): + return QueueStore.getMessage(_) + + # Function to add messages to the queue + def addMessage(message: str): + return QueueStore.addMessage(_, message) + + # Function to check if the queue is empty + def isEmpty(): + return QueueStore.isEmpty(_) + + return _, getMessage, addMessage, isEmpty diff --git a/aios/hooks/modules/memory.py b/aios/hooks/modules/memory.py new file mode 100644 index 000000000..3a61c5cab --- /dev/null +++ b/aios/hooks/modules/memory.py @@ -0,0 +1,42 @@ +from typing import Tuple + +from aios.hooks.types.memory import ( + MemoryRequestQueue, + MemoryRequestQueueGetMessage, + MemoryRequestQueueAddMessage, + MemoryRequestQueueCheckEmpty +) +from aios.hooks.utils.validate import validate +from aios.hooks.stores import queue as QueueStore + +def useMemoryRequestQueue() -> ( + Tuple[MemoryRequestQueue, MemoryRequestQueueGetMessage, MemoryRequestQueueAddMessage, MemoryRequestQueueCheckEmpty] +): + """ + Creates and returns a queue for Memory-related requests along with helper methods to manage the queue. + + Returns: + Tuple: A tuple containing the Memory request queue, get message function, add message function, and check queue empty function. + """ + # r_str = ( + # generate_random_string() + # ) # Generate a random string for queue identification + r_str = "memory" + _ = MemoryRequestQueue() + + # Store the LLM request queue in QueueStore + QueueStore.REQUEST_QUEUE[r_str] = _ + + # Function to get messages from the queue + def getMessage(): + return QueueStore.getMessage(_) + + # Function to add messages to the queue + def addMessage(message: str): + return QueueStore.addMessage(_, message) + + # Function to check if the queue is empty + def isEmpty(): + return QueueStore.isEmpty(_) + + return _, getMessage, addMessage, isEmpty \ No newline at end of file diff --git a/aios/hooks/modules/scheduler.py b/aios/hooks/modules/scheduler.py new file mode 100644 index 000000000..4364c67f7 --- /dev/null +++ b/aios/hooks/modules/scheduler.py @@ -0,0 +1,82 @@ +from typing import Any, Tuple, Callable, Dict +from random import randint + +from aios.llm_core.llms import LLM +from aios.hooks.types.scheduler import ( + # AgentSubmitDeclaration, + # FactoryParams, + # LLMParams, + SchedulerParams, + # LLMRequestQueue, + # QueueGetMessage, + # QueueAddMessage, + # QueueCheckEmpty, +) + +from contextlib import contextmanager + +from aios.hooks.utils.validate import validate +from aios.hooks.stores import queue as QueueStore, processes as ProcessStore +from aios.scheduler.fifo_scheduler import FIFOScheduler + + +@validate(SchedulerParams) +def useFIFOScheduler( + params: SchedulerParams, +) -> Tuple[Callable[[], None], Callable[[], None]]: + """ + Initialize and return a First-In-First-Out (FIFO) scheduler with start and stop functions. + + Args: + params (SchedulerParams): Parameters required for the scheduler. + + Returns: + Tuple: A tuple containing the start and stop functions for the scheduler. + """ + if params.get_llm_request is None: + # Import a global message retrieval function if not provided + from aios.hooks.stores._global import global_llm_req_queue_get_message + + params.get_llm_request = global_llm_req_queue_get_message + + if params.get_memory_request is None: + # Import a global message retrieval function if not provided + from aios.hooks.stores._global import global_memory_req_queue_get_message + + params.get_memory_request = global_memory_req_queue_get_message + + scheduler = FIFOScheduler(**params.model_dump()) + + # Function to start the scheduler + def startScheduler(): + scheduler.start() + + # Function to stop the scheduler + def stopScheduler(): + scheduler.stop() + + return startScheduler, stopScheduler + + +@contextmanager +@validate(SchedulerParams) +def fifo_scheduler(params: SchedulerParams): + """ + A context manager that starts and stops a FIFO scheduler. + + Args: + params (SchedulerParams): The parameters for the scheduler. + """ + if params.get_llm_request is None: + from aios.hooks.stores._global import global_llm_req_queue_get_message + params.get_llm_request = global_llm_req_queue_get_message + + if params.get_memory_request is None: + from aios.hooks.stores._global import global_memory_req_queue_get_message + params.get_memory_request = global_memory_req_queue_get_message + + scheduler = FIFOScheduler(**params.model_dump()) + + scheduler.start() + yield + scheduler.stop() diff --git a/aios/hooks/request.py b/aios/hooks/request.py index afbd4ccf1..306632ba5 100755 --- a/aios/hooks/request.py +++ b/aios/hooks/request.py @@ -3,11 +3,14 @@ import random import time -from aios.hooks.stores._global import global_llm_req_queue_add_message +from aios.hooks.stores._global import ( + global_llm_req_queue_add_message, + global_memory_req_queue_add_message, +) class AgentRequest(Thread): - def __init__(self, agent_name, query): + def __init__(self, agent_name, request_data): """Agent Process Args: @@ -16,9 +19,9 @@ def __init__(self, agent_name, query): """ super().__init__(name=agent_name) self.agent_name = agent_name - self.query = query + self.request_data = request_data self.event = Event() - self.pid: int = None + self.pid = None self.status = None self.response = None self.time_limit = None @@ -92,15 +95,33 @@ def run(self): self.set_pid(self.native_id) self.event.wait() + class LLMRequest(AgentRequest): pass def send_request(agent_name, query): - agent_request = AgentRequest( - agent_name=agent_name, - query=query - ) + if query.action_type == "message_llm": + # retrive memory + llm_response, _, _, _, _ = call_llm( + agent_name=agent_name, request_data=query + ) # chat with llm + return (llm_response, _, _, _, _) + # save memory + + elif query.action_type == "call_tool": + # retrive memory + llm_response, _, _, _, _ = call_llm( + agent_name=agent_name, request_data=query + ) # chat with llm + return (llm_response, _, _, _, _) + + elif query.action_type == "operate_file": + pass + + +def call_llm(agent_name, request_data): + agent_request = AgentRequest(agent_name=agent_name, request_data=request_data) agent_request.set_status("active") completed_response, start_times, end_times, waiting_times, turnaround_times = ( @@ -110,6 +131,7 @@ def send_request(agent_name, query): [], [], ) + # completed_response = "" while agent_request.get_status() != "done": current_time = time.time() @@ -122,9 +144,58 @@ def send_request(agent_name, query): agent_request.join() completed_response = agent_request.get_response() - + + if agent_request.get_status() != "done": + pass + + start_time = agent_request.get_start_time() + end_time = agent_request.get_end_time() + waiting_time = start_time - agent_request.get_created_time() + turnaround_time = end_time - agent_request.get_created_time() + + start_times.append(start_time) + end_times.append(end_time) + waiting_times.append(waiting_time) + turnaround_times.append(turnaround_time) + + # return completed_response + return ( + completed_response, + start_times, + end_times, + waiting_times, + turnaround_times, + ) + + +def call_memory(agent_name, request_data): + agent_request = AgentRequest(agent_name=agent_name, request_data=request_data) + agent_request.set_status("active") + + completed_response, start_times, end_times, waiting_times, turnaround_times = ( + "", + [], + [], + [], + [], + ) + # completed_response = "" + + while agent_request.get_status() != "done": + current_time = time.time() + agent_request.set_created_time(current_time) + agent_request.set_response(None) + + global_memory_req_queue_add_message(agent_request) + + agent_request.start() + agent_request.join() + + completed_response = agent_request.get_response() + if agent_request.get_status() != "done": pass + start_time = agent_request.get_start_time() end_time = agent_request.get_end_time() waiting_time = start_time - agent_request.get_created_time() @@ -135,10 +206,11 @@ def send_request(agent_name, query): waiting_times.append(waiting_time) turnaround_times.append(turnaround_time) + # return completed_response return ( completed_response, start_times, end_times, waiting_times, turnaround_times, - ) \ No newline at end of file + ) diff --git a/aios/hooks/starter.py b/aios/hooks/starter.py new file mode 100644 index 000000000..a1731d6ca --- /dev/null +++ b/aios/hooks/starter.py @@ -0,0 +1,54 @@ +from contextlib import contextmanager +from typing import Tuple, Callable, Dict, Any +from .modules.llm import useKernel +from .modules.agent import useFactory +from .modules.scheduler import fifo_scheduler + + +@contextmanager +def aios_starter( + llm_name: str, + max_gpu_memory: str, + eval_device: str, + max_new_tokens: int, + scheduler_log_mode: str, + agent_log_mode: str, + llm_kernel_log_mode: str, + use_backend: str, +) -> Tuple[Callable[[str, str], int], Callable[[str], Dict[str, Any]]]: + """ + Starts a LLM kernel and a scheduler for running agents, returning functions to submit agents and await their execution. + + Args: + llm_name (str): The name of the LLM kernel to use. + max_gpu_memory (str): The maximum amount of GPU memory to use. + eval_device (str): The device to evaluate the LLM on. + max_new_tokens (int): The maximum number of new tokens to generate. + scheduler_log_mode (str): The log mode for the scheduler. + agent_log_mode (str): The log mode for the agents. + llm_kernel_log_mode (str): The log mode for the LLM kernel. + use_backend (str): The backend to use for running the LLM kernel. + + Yields: + Tuple: A tuple containing the submitAgent and awaitAgentExecution functions. + """ + llm = useKernel( + llm_name=llm_name, + max_gpu_memory=max_gpu_memory, + eval_device=eval_device, + max_new_tokens=max_new_tokens, + log_mode=llm_kernel_log_mode, + use_backend=use_backend, + ) + + submit_agent, await_agent_execution = useFactory( + log_mode=agent_log_mode, max_workers=64 + ) + + with fifo_scheduler( + llm=llm, + log_mode=scheduler_log_mode, + get_llm_request=None, + get_memory_request=None, + ): + yield submit_agent, await_agent_execution diff --git a/aios/hooks/stores/_global.py b/aios/hooks/stores/_global.py index 775df38cf..9f7f905ee 100644 --- a/aios/hooks/stores/_global.py +++ b/aios/hooks/stores/_global.py @@ -1,5 +1,19 @@ -#global vars +# global variables -from aios.hooks.llm import useLLMRequestQueue +from aios.hooks.modules.llm import useLLMRequestQueue -global_llm_req_queue, global_llm_req_queue_get_message, global_llm_req_queue_add_message, global_llm_req_queue_is_empty = useLLMRequestQueue() +from aios.hooks.modules.memory import useMemoryRequestQueue + +( + global_llm_req_queue, + global_llm_req_queue_get_message, + global_llm_req_queue_add_message, + global_llm_req_queue_is_empty, +) = useLLMRequestQueue() + +( + global_memory_req_queue, + global_memory_req_queue_get_message, + global_memory_req_queue_add_message, + global_memory_req_queue_is_empty, +) = useMemoryRequestQueue() diff --git a/aios/hooks/stores/queue.py b/aios/hooks/stores/queue.py index e3ca58a0d..74e03b782 100644 --- a/aios/hooks/stores/queue.py +++ b/aios/hooks/stores/queue.py @@ -1,14 +1,14 @@ -from aios.hooks.types.llm import LLMRequestQueue +from queue import Queue -LLM_REQUEST_QUEUE: dict[str, LLMRequestQueue] = {} +REQUEST_QUEUE: dict[str, Queue] = {} -def getMessage(q: LLMRequestQueue): +def getMessage(q: Queue): return q.get(block=True, timeout=0.1) -def addMessage(q: LLMRequestQueue, message: str): +def addMessage(q: Queue, message: str): q.put(message) return None -def isEmpty(q: LLMRequestQueue): +def isEmpty(q: Queue): return q.empty() diff --git a/aios/hooks/types/agent.py b/aios/hooks/types/agent.py new file mode 100644 index 000000000..f85daa29a --- /dev/null +++ b/aios/hooks/types/agent.py @@ -0,0 +1,16 @@ +from pydantic import BaseModel +from typing import Any, TypeAlias, Callable + +class AgentParserParams(BaseModel): + llm: Any + query: str + + +class FactoryParams(BaseModel): + log_mode: str = ("console",) + max_workers: int = 500 + + +class AgentSubmitDeclaration(BaseModel): + agent_name: str + task_input: str | int | float | dict | tuple | list \ No newline at end of file diff --git a/aios/hooks/types/llm.py b/aios/hooks/types/llm.py index 70224a5cb..35f0f4c43 100644 --- a/aios/hooks/types/llm.py +++ b/aios/hooks/types/llm.py @@ -1,36 +1,18 @@ from pydantic import BaseModel from typing import Any, TypeAlias, Callable - from queue import Queue LLMRequestQueue: TypeAlias = Queue -QueueGetMessage: TypeAlias = Callable[[], None] -QueueAddMessage: TypeAlias = Callable[[str], None] -QueueCheckEmpty: TypeAlias = Callable[[], bool] +LLMRequestQueueGetMessage: TypeAlias = Callable[[], None] +LLMRequestQueueAddMessage: TypeAlias = Callable[[str], None] +LLMRequestQueueCheckEmpty: TypeAlias = Callable[[], bool] + class LLMParams(BaseModel): llm_name: str - max_gpu_memory: dict | None = None, - eval_device: str | None = None, - max_new_tokens: int = 256, - log_mode: str = "console", + max_gpu_memory: dict | None = (None,) + eval_device: str | None = (None,) + max_new_tokens: int = (256,) + log_mode: str = ("console",) use_backend: str | None = None - - -class SchedulerParams(BaseModel): - llm: Any - log_mode: str - get_queue_message: QueueGetMessage | None - -class AgentParserParams(BaseModel): - llm: Any - query: str - -class FactoryParams(BaseModel): - log_mode: str = "console", - max_workers: int = 500 - -class AgentSubmitDeclaration(BaseModel): - agent_name: str - task_input: str | int | float | dict | tuple | list diff --git a/aios/hooks/types/memory.py b/aios/hooks/types/memory.py new file mode 100644 index 000000000..3cc6f6e58 --- /dev/null +++ b/aios/hooks/types/memory.py @@ -0,0 +1,9 @@ +from pydantic import BaseModel +from typing import Any, TypeAlias, Callable +from queue import Queue + +MemoryRequestQueue: TypeAlias = Queue + +MemoryRequestQueueGetMessage: TypeAlias = Callable[[], None] +MemoryRequestQueueAddMessage: TypeAlias = Callable[[str], None] +MemoryRequestQueueCheckEmpty: TypeAlias = Callable[[], bool] \ No newline at end of file diff --git a/aios/hooks/types/scheduler.py b/aios/hooks/types/scheduler.py new file mode 100644 index 000000000..622dbe8b4 --- /dev/null +++ b/aios/hooks/types/scheduler.py @@ -0,0 +1,11 @@ +from pydantic import BaseModel +from typing import Any, TypeAlias, Callable + +from .llm import LLMRequestQueueGetMessage +from .memory import MemoryRequestQueueGetMessage + +class SchedulerParams(BaseModel): + llm: Any + log_mode: str + get_llm_request: LLMRequestQueueGetMessage | None + get_memory_request: MemoryRequestQueueGetMessage | None \ No newline at end of file diff --git a/aios/hooks/utils/__init__.py b/aios/hooks/utils/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/aios/hooks/parser.py b/aios/hooks/utils/parser.py similarity index 100% rename from aios/hooks/parser.py rename to aios/hooks/utils/parser.py diff --git a/aios/hooks/utils.py b/aios/hooks/utils/utils.py similarity index 100% rename from aios/hooks/utils.py rename to aios/hooks/utils/utils.py diff --git a/aios/hooks/validate.py b/aios/hooks/utils/validate.py similarity index 100% rename from aios/hooks/validate.py rename to aios/hooks/utils/validate.py diff --git a/aios/llm_core/llm_classes/claude_llm.py b/aios/llm_core/llm_classes/claude_llm.py index 08e3121cd..50c1464b8 100644 --- a/aios/llm_core/llm_classes/claude_llm.py +++ b/aios/llm_core/llm_classes/claude_llm.py @@ -48,10 +48,10 @@ def load_llm_and_tokenizer(self) -> None: def process(self, agent_request: Any, temperature: float = 0.0) -> None: """ - Process a query using the Claude model. + Process a request_data using the Claude model. Args: - agent_request (Any): The agent process containing the query and tools. + agent_request (Any): The agent process containing the request_data and tools. temperature (float, optional): Sampling temperature for generation. Raises: @@ -62,8 +62,8 @@ def process(self, agent_request: Any, temperature: float = 0.0) -> None: assert re.search(r'claude', self.model_name, re.IGNORECASE), "Model name must contain 'claude'" agent_request.set_status("executing") agent_request.set_start_time(time.time()) - messages = agent_request.query.messages - tools = agent_request.query.tools + messages = agent_request.request_data.messages + tools = agent_request.request_data.tools self.logger.log(f"{messages}", level="info") self.logger.log(f"{agent_request.agent_name} is switched to executing.", level="executing") diff --git a/aios/llm_core/llm_classes/gemini_llm.py b/aios/llm_core/llm_classes/gemini_llm.py index eec3dc7a0..7c3718fde 100644 --- a/aios/llm_core/llm_classes/gemini_llm.py +++ b/aios/llm_core/llm_classes/gemini_llm.py @@ -58,9 +58,9 @@ def process(self, agent_request.set_status("executing") agent_request.set_start_time(time.time()) - messages = agent_request.query.messages - tools = agent_request.query.tools - message_return_type = agent_request.query.message_return_type + messages = agent_request.request_data.messages + tools = agent_request.request_data.tools + message_return_type = agent_request.request_data.message_return_type if tools: messages = self.tool_calling_input_format(messages, tools) diff --git a/aios/llm_core/llm_classes/gpt_llm.py b/aios/llm_core/llm_classes/gpt_llm.py index c5c54e1cc..e9c1cb613 100644 --- a/aios/llm_core/llm_classes/gpt_llm.py +++ b/aios/llm_core/llm_classes/gpt_llm.py @@ -53,14 +53,14 @@ def process(self, agent_request, temperature=0.0): """ wrapper around openai api """ agent_request.set_status("executing") agent_request.set_start_time(time.time()) - messages = agent_request.query.messages + messages = agent_request.request_data.messages try: response = self.model.chat.completions.create( model=self.model_name, messages=messages, - tools=agent_request.query.tools, - # tool_choice = "required" if agent_request.query.tools else None, + tools=agent_request.request_data.tools, + # tool_choice = "required" if agent_request.request_data.tools else None, max_tokens=self.max_new_tokens, ) response_message = response.choices[0].message.content diff --git a/aios/llm_core/llm_classes/hf_native_llm.py b/aios/llm_core/llm_classes/hf_native_llm.py index 5be371158..df6eaf8f2 100644 --- a/aios/llm_core/llm_classes/hf_native_llm.py +++ b/aios/llm_core/llm_classes/hf_native_llm.py @@ -48,9 +48,9 @@ def process(self, level = "executing" ) - messages = agent_request.query.messages - tools = agent_request.query.tools - message_return_type = agent_request.query.message_return_type + messages = agent_request.request_data.messages + tools = agent_request.request_data.tools + message_return_type = agent_request.request_data.message_return_type """ context_manager works only with open llms """ if self.context_manager.check_restoration(agent_request.get_pid()): diff --git a/aios/llm_core/llm_classes/ollama_llm.py b/aios/llm_core/llm_classes/ollama_llm.py index e15db4f49..ed3e4011a 100644 --- a/aios/llm_core/llm_classes/ollama_llm.py +++ b/aios/llm_core/llm_classes/ollama_llm.py @@ -35,9 +35,9 @@ def process(self, """ simple wrapper around ollama functions """ agent_request.set_status("executing") agent_request.set_start_time(time.time()) - messages = agent_request.query.messages - tools = agent_request.query.tools - message_return_type = agent_request.query.message_return_type + messages = agent_request.request_data.messages + tools = agent_request.request_data.tools + message_return_type = agent_request.request_data.message_return_type self.logger.log( f"{agent_request.agent_name} is switched to executing.\n", level = "executing" diff --git a/aios/llm_core/llm_classes/vllm.py b/aios/llm_core/llm_classes/vllm.py index 8618bfaae..31de7da78 100644 --- a/aios/llm_core/llm_classes/vllm.py +++ b/aios/llm_core/llm_classes/vllm.py @@ -61,9 +61,9 @@ def process(self, level = "executing" ) - messages = agent_request.query.messages - tools = agent_request.query.tools - message_return_type = agent_request.query.message_return_type + messages = agent_request.request_data.messages + tools = agent_request.request_data.tools + message_return_type = agent_request.request_data.message_return_type if tools: messages = self.tool_calling_input_format(messages, tools) diff --git a/aios/scheduler/fifo_scheduler.py b/aios/scheduler/fifo_scheduler.py index 2faafba6c..d4ca0ebed 100644 --- a/aios/scheduler/fifo_scheduler.py +++ b/aios/scheduler/fifo_scheduler.py @@ -2,73 +2,119 @@ # similar fashion to the round robin scheduler. However, the timeout is 1 second # instead of 0.05 seconds. -from .base import BaseScheduler -from aios.hooks.types.llm import QueueGetMessage +from aios.hooks.types.llm import LLMRequestQueueGetMessage +from aios.hooks.types.memory import MemoryRequestQueueGetMessage from queue import Queue, Empty import traceback import time +from aios.utils.logger import SchedulerLogger -class FIFOScheduler(BaseScheduler): - def __init__(self, llm, log_mode, get_queue_message: QueueGetMessage): - super().__init__(llm, log_mode) +from threading import Thread + + +class FIFOScheduler: + def __init__( + self, + llm, + # memory_manager, + log_mode, + get_llm_request: LLMRequestQueueGetMessage, + get_memory_request: MemoryRequestQueueGetMessage, + ): self.agent_process_queue = Queue() - self.get_queue_message = get_queue_message + self.get_llm_request = get_llm_request + self.get_memory_request = get_memory_request + self.active = False # start/stop the scheduler + self.log_mode = log_mode + self.logger = self.setup_logger() + # self.thread = Thread(target=self.run) + self.request_processors = { + "llm_request_processor": Thread(target=self.run_llm_request), + # "memory_request_processor": Thread(self.run_memory_request) + } + self.llm = llm + # self.memory_manager = memory_manager + + def start(self): + """start the scheduler""" + self.active = True + for name, thread_value in self.request_processors.items(): + thread_value.start() - def run(self): + def stop(self): + """stop the scheduler""" + self.active = False + for name, thread_value in self.request_processors.items(): + thread_value.join() + + def setup_logger(self): + logger = SchedulerLogger("Scheduler", self.log_mode) + return logger + + def run_llm_request(self): while self.active: try: # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty - agent_request = self.get_queue_message() + agent_request = self.get_llm_request() agent_request.set_status("executing") self.logger.log( f"{agent_request.agent_name} is executing. \n", "execute" ) agent_request.set_start_time(time.time()) - - self.execute_request(agent_request) + + response = self.llm.address_request(agent_request) + agent_request.set_response(response) + + # self.llm.address_request(agent_request) + + agent_request.event.set() + agent_request.set_status("done") + agent_request.set_end_time(time.time()) self.logger.log( - f"Current request of {agent_request.agent_name} is done. Thread ID is {agent_request.get_pid()}\n", "done" + f"Current request of {agent_request.agent_name} is done. Thread ID is {agent_request.get_pid()}\n", + "done", ) # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty - agent_request = self.get_queue_message() + + except Empty: + pass + + except Exception: + traceback.print_exc() + + def run_memory_request(self): + while self.active: + try: + # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty + agent_request = self.get_memory_request() agent_request.set_status("executing") self.logger.log( f"{agent_request.agent_name} is executing. \n", "execute" ) agent_request.set_start_time(time.time()) - - self.execute_request(agent_request) + + response = self.memory_manager.address_request(agent_request) + agent_request.set_response(response) + + # self.llm.address_request(agent_request) + + agent_request.event.set() + agent_request.set_status("done") + agent_request.set_end_time(time.time()) self.logger.log( - f"Current request of {agent_request.agent_name} is done. Thread ID is {agent_request.get_pid()}\n", "done" + f"Current request of {agent_request.agent_name} is done. Thread ID is {agent_request.get_pid()}\n", + "done", ) + # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty except Empty: pass - except Exception: traceback.print_exc() - - def execute_request(self, agent_request): - action_type = agent_request.query.action_type - - if action_type in ["message_llm", "call_tool"]: - response = self.llm.address_request(agent_request) - # print(response) - agent_request.set_response(response) - - # self.llm.address_request(agent_request) - - # elif action_type == "operate_file": - # api_calls = self.lsfs_parser.parse(agent_request) - # response = self.lsfs.execute_calls(api_calls) - # agent_request.set_response(response) - agent_request.event.set() - agent_request.set_status("done") - agent_request.set_end_time(time.time()) diff --git a/pyopenagi/agents/agent_factory.py b/pyopenagi/agents/agent_factory.py index 686986f4d..a2da44555 100755 --- a/pyopenagi/agents/agent_factory.py +++ b/pyopenagi/agents/agent_factory.py @@ -7,40 +7,41 @@ class AgentFactory: - def __init__(self, - # agent_process_queue, - # agent_process_factory, - agent_log_mode - ): - self.max_aid = 256 + def __init__( + self, + # agent_process_queue, + # agent_process_factory, + agent_log_mode + ): + # self.max_aid = 256 # self.llm = llm - self.aid_pool = [i for i in range(self.max_aid)] - heapq.heapify(self.aid_pool) + # self.aid_pool = [i for i in range(self.max_aid)] + # heapq.heapify(self.aid_pool) # self.agent_process_queue = agent_process_queue # self.agent_process_factory = agent_process_factory - self.current_agents = {} + # self.current_agents = {} - self.current_agents_lock = Lock() + # self.current_agents_lock = Lock() - self.terminate_signal = Event() + # self.terminate_signal = Event() self.agent_log_mode = agent_log_mode - self.manager = AgentManager('https://my.aios.foundation/') + self.manager = AgentManager("https://my.aios.foundation/") def snake_to_camel(self, snake_str): - components = snake_str.split('_') - return ''.join(x.title() for x in components) + components = snake_str.split("_") + return "".join(x.title() for x in components) def list_agents(self): agent_list = self.manager.list_available_agents() - + for agent in agent_list: print(agent) def load_agent_instance(self, compressed_name: str): - name_split = compressed_name.split('/') + name_split = compressed_name.split("/") agent_class = self.manager.load_agent(*name_split) return agent_class @@ -57,22 +58,18 @@ def activate_agent(self, agent_name: str, task_input): # if not interactor.check_reqs_installed(agent_name): # interactor.install_agent_reqs(agent_name) - agent_name = '/'.join( - self.manager.download_agent( - *agent_name.split('/') - )) + agent_name = "/".join(self.manager.download_agent(*agent_name.split("/"))) # we instantiate the agent directly from the class agent_class = self.load_agent_instance(agent_name) agent = agent_class( - agent_name = agent_name, - task_input = task_input, + agent_name=agent_name, + task_input=task_input, # agent_process_factory = self.agent_process_factory, - log_mode = self.agent_log_mode + log_mode=self.agent_log_mode, ) - # set the identifier for the agent # aid = heapq.heappop(self.aid_pool) # agent.set_aid(aid) @@ -85,13 +82,10 @@ def activate_agent(self, agent_name: str, task_input): return agent def run_agent(self, agent_name, task_input): - agent = self.activate_agent( - agent_name=agent_name, - task_input=task_input - ) + agent = self.activate_agent(agent_name=agent_name, task_input=task_input) # print(task_input) output = agent.run() - self.deactivate_agent(agent.get_aid()) + # self.deactivate_agent(agent.get_aid()) return output def print_agent(self): @@ -102,31 +96,30 @@ def print_agent(self): created_time = agent.created_time status = agent.status memory_usage = f"{asizeof.asizeof(agent)} bytes" - data.append( - [id, agent_name, created_time, status, memory_usage] - ) + data.append([id, agent_name, created_time, status, memory_usage]) self.print(headers=headers, data=data) - def print(self, headers, data): # align output column_widths = [ - max(len(str(row[i])) for row in [headers] + data) for i in range(len(headers)) + max(len(str(row[i])) for row in [headers] + data) + for i in range(len(headers)) ] - print("+" + "-" * (sum(column_widths) + len(headers) * 3 - 3 ) + "+") + print("+" + "-" * (sum(column_widths) + len(headers) * 3 - 3) + "+") print(self.format_row(headers, column_widths)) print("=" * (sum(column_widths) + len(headers) * 3 - 1)) for i, row in enumerate(data): print(self.format_row(row, column_widths)) if i < len(data): print("-" * (sum(column_widths) + len(headers) * 3 - 1)) - print("+" + "-" * (sum(column_widths) + len(headers) * 3 - 3 ) + "+") - + print("+" + "-" * (sum(column_widths) + len(headers) * 3 - 3) + "+") def format_row(self, row, widths, align="<"): - row_str = " | ".join(f"{str(item):{align}{widths[i]}}" for i, item in enumerate(row)) + row_str = " | ".join( + f"{str(item):{align}{widths[i]}}" for i, item in enumerate(row) + ) return row_str def deactivate_agent(self, aid): self.current_agents.pop(aid) - heapq.heappush(self.aid_pool, aid) \ No newline at end of file + heapq.heappush(self.aid_pool, aid) From e89fb2b76b9f1e61c3166bb2cb091ef7e29bc7df Mon Sep 17 00:00:00 2001 From: dongyuanjushi Date: Thu, 17 Oct 2024 11:32:12 -0400 Subject: [PATCH 15/41] update agents --- pyopenagi/agents/agent_factory.py | 19 ++++++++++--------- pyopenagi/queues/base_queue.py | 17 ----------------- pyopenagi/queues/llm_request_queue.py | 4 ---- 3 files changed, 10 insertions(+), 30 deletions(-) delete mode 100644 pyopenagi/queues/base_queue.py delete mode 100644 pyopenagi/queues/llm_request_queue.py diff --git a/pyopenagi/agents/agent_factory.py b/pyopenagi/agents/agent_factory.py index 686986f4d..c608a0624 100755 --- a/pyopenagi/agents/agent_factory.py +++ b/pyopenagi/agents/agent_factory.py @@ -12,18 +12,18 @@ def __init__(self, # agent_process_factory, agent_log_mode ): - self.max_aid = 256 + # self.max_aid = 256 # self.llm = llm - self.aid_pool = [i for i in range(self.max_aid)] - heapq.heapify(self.aid_pool) + # self.aid_pool = [i for i in range(self.max_aid)] + # heapq.heapify(self.aid_pool) # self.agent_process_queue = agent_process_queue # self.agent_process_factory = agent_process_factory - self.current_agents = {} + # self.current_agents = {} - self.current_agents_lock = Lock() + # self.current_agents_lock = Lock() - self.terminate_signal = Event() + # self.terminate_signal = Event() self.agent_log_mode = agent_log_mode @@ -91,7 +91,7 @@ def run_agent(self, agent_name, task_input): ) # print(task_input) output = agent.run() - self.deactivate_agent(agent.get_aid()) + # self.deactivate_agent(agent.get_aid()) return output def print_agent(self): @@ -128,5 +128,6 @@ def format_row(self, row, widths, align="<"): return row_str def deactivate_agent(self, aid): - self.current_agents.pop(aid) - heapq.heappush(self.aid_pool, aid) \ No newline at end of file + # self.current_agents.pop(aid) + # heapq.heappush(self.aid_pool, aid) + pass \ No newline at end of file diff --git a/pyopenagi/queues/base_queue.py b/pyopenagi/queues/base_queue.py deleted file mode 100644 index 377f69319..000000000 --- a/pyopenagi/queues/base_queue.py +++ /dev/null @@ -1,17 +0,0 @@ -import queue - -class BaseQueue: - - _queue = queue.Queue() - - @classmethod - def add_message(cls, message): - cls._queue.put(message) - - @classmethod - def get_message(cls): - return cls._queue.get(block=True, timeout=1) - - @classmethod - def is_empty(cls): - return cls._queue.empty() diff --git a/pyopenagi/queues/llm_request_queue.py b/pyopenagi/queues/llm_request_queue.py deleted file mode 100644 index 3555f5cb1..000000000 --- a/pyopenagi/queues/llm_request_queue.py +++ /dev/null @@ -1,4 +0,0 @@ -from .base_queue import BaseQueue - -class LLMRequestQueue(BaseQueue): - pass From 2506977137fbf58931cf6d0d785ccd190167e8b7 Mon Sep 17 00:00:00 2001 From: 2020-qqtcg Date: Fri, 18 Oct 2024 15:10:11 +0800 Subject: [PATCH 16/41] feat: standard agent --- .../experiment/standard/action/action.py | 4 + .../experiment/standard/action/action_code.py | 0 .../experiment/standard/action/action_tool.py | 60 +++++++++++++++ pyopenagi/agents/experiment/standard/agent.py | 77 ++++++++++++++++--- .../agents/experiment/standard/config.json | 18 +++++ .../standard/memory/short_term_memory.py | 3 + .../experiment/standard/planning/planning.py | 38 ++++++++- .../experiment/standard/prompt/__init__.py | 0 .../standard/prompt/framework_prompt.py | 30 ++++++++ .../experiment/standard/utils/__init__.py | 0 .../experiment/standard/utils/config.py | 25 ++++++ .../experiment/standard/utils/str_utils.py | 3 + 12 files changed, 245 insertions(+), 13 deletions(-) create mode 100644 pyopenagi/agents/experiment/standard/action/action_code.py create mode 100644 pyopenagi/agents/experiment/standard/action/action_tool.py create mode 100644 pyopenagi/agents/experiment/standard/prompt/__init__.py create mode 100644 pyopenagi/agents/experiment/standard/prompt/framework_prompt.py create mode 100644 pyopenagi/agents/experiment/standard/utils/__init__.py create mode 100644 pyopenagi/agents/experiment/standard/utils/config.py create mode 100644 pyopenagi/agents/experiment/standard/utils/str_utils.py diff --git a/pyopenagi/agents/experiment/standard/action/action.py b/pyopenagi/agents/experiment/standard/action/action.py index 257584272..56b62c265 100644 --- a/pyopenagi/agents/experiment/standard/action/action.py +++ b/pyopenagi/agents/experiment/standard/action/action.py @@ -6,3 +6,7 @@ class Action(ABC): @abstractmethod def __call__(self, *args, **kwargs): pass + + @abstractmethod + def format_prompt(self): + pass diff --git a/pyopenagi/agents/experiment/standard/action/action_code.py b/pyopenagi/agents/experiment/standard/action/action_code.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyopenagi/agents/experiment/standard/action/action_tool.py b/pyopenagi/agents/experiment/standard/action/action_tool.py new file mode 100644 index 000000000..af432bb9d --- /dev/null +++ b/pyopenagi/agents/experiment/standard/action/action_tool.py @@ -0,0 +1,60 @@ +import importlib +from typing import List, Any, Optional +from pydantic.v1 import BaseModel, root_validator +from pyopenagi.agents.experiment.standard.action.action import Action +from pyopenagi.agents.experiment.standard.utils.config import Config +from pyopenagi.agents.experiment.standard.utils.str_utils import snake_to_camel + + +class ActionTool(Action, BaseModel): + + config: Config + tools: Optional[List] + tools_format: Optional[List] + type: str = "TOOL" + + def __call__(self, tool_call: dict) -> Any: + if tool_call is None: + return + + function_name = tool_call["name"] + function_param = tool_call["parameters"] + try: + function_call = self.tools[function_name] + function_response = function_call.run(function_param) + + except TypeError: + function_response = f"Call function {function_name} failed. Parameters {function_param} is invalid." + + return function_response + + @root_validator(pre=True) + def init_tools(self): + self._init_tools_from_config() + + def _init_tools_from_config(self): + tool_names = self.config.tools + if tool_names == "None": + return + + for tool_name in tool_names: + org, name = tool_name.split("/") + module_name = ".".join(["pyopenagi", "tools", org, name]) + class_name = snake_to_camel(name) + + tool_module = importlib.import_module(module_name) + tool_class = getattr(tool_module, class_name) + + self.tools[name] = tool_class() + tool_format = tool_class().get_tool_call_format() + self.tools_format.append(tool_format) + + def format_prompt(self): + return { + "name": "tool use", + "description": "" + } + + @staticmethod + def display(): + return False diff --git a/pyopenagi/agents/experiment/standard/agent.py b/pyopenagi/agents/experiment/standard/agent.py index 8e3c9e002..624a7f333 100644 --- a/pyopenagi/agents/experiment/standard/agent.py +++ b/pyopenagi/agents/experiment/standard/agent.py @@ -1,9 +1,11 @@ import time from typing import List - from aios.hooks.request import send_request +from pyopenagi.agents.experiment.standard.action.action_tool import ActionTool from pyopenagi.agents.experiment.standard.memory.short_term_memory import ShortTermMemory from pyopenagi.agents.experiment.standard.planning.planning import Planning, DefaultPlanning +from pyopenagi.agents.experiment.standard.prompt.framework_prompt import STANDARD_PROMPT +from pyopenagi.agents.experiment.standard.utils.config import load_config from pyopenagi.utils.chat_template import Query, Response from pyopenagi.utils.logger import AgentLogger @@ -13,14 +15,18 @@ class StandardAgent: def __init__(self, agent_name: str, task_input: str, log_mode: str): # Init module self.planning: Planning | None = None - self.actions = None + self.actions = {} self.communication = None self.memory = None self.short_term_memory = ShortTermMemory() + # Init config and tool + self.config = load_config() + # Init agent base info self.agent_name = agent_name self.task_input = task_input + self._init_framework_prompt() # Init logger self.logger = AgentLogger(agent_name, log_mode) @@ -38,8 +44,45 @@ def __init__(self, agent_name: str, task_input: str, log_mode: str): def messages(self): return self.short_term_memory.messages - def system_prompt(self) -> str: - return """You are a smart agent.""" + @property + def tools_format(self): + if "TOOL" in self.actions: + return self.actions["TOOL"].tools_format + else: + return None + + def custom_prompt(self) -> str: + pass + + def _init_framework_prompt(self): + # Action + action_prompt = self._action_prompt() + planning_prompt = self._planning_prompt() + + framework_prompt = STANDARD_PROMPT.format( + action=action_prompt, + planning=planning_prompt, + ) + + self.short_term_memory.remember(role="system", content=framework_prompt) + + def _action_prompt(self) -> str: + action_prompt = "" + for action in self.actions: + if action.disply: + name = action.format_prompt()["name"] + description = action.format_prompt()["description"] + action_prompt += f"- {name}: {description}\n" + + return action_prompt + + def _planning_prompt(self) -> str: + planning_prompt = "" + + name = self.planning.format_prompt()["name"] + description = self.planning.format_prompt()["description"] + planning_prompt += f"- {name}: {description}\n" + return planning_prompt def init_module(self): return @@ -54,24 +97,38 @@ def init_memory(self, memory): return def init_actions(self, actions): - return + action_tool = ActionTool() + self.actions[action_tool.type] = action_tool def planning(self) -> dict: # Select suitable messages messages = self.short_term_memory.recall() - planning = DefaultPlanning() - result = planning(messages, self.tools) + planning = DefaultPlanning(self.request) + result = planning(messages, self.tools_format) return result def run(self): # Init system prompt and task - self.short_term_memory.remember("system", self.system_prompt()) + if custom_prompt := self.custom_prompt(): + self.short_term_memory.remember("system", custom_prompt) self.short_term_memory.remember("user", self.task_input) - # Run planning - # planning_result = self.planning() + while not self._is_terminate(): + # Run planning + planning_result = self.planning() + if action_type := planning_result.action_type: + action = self.actions[action_type] + action_param = planning_result.action_param + response, tool_call_id = action(**action_param) + self.short_term_memory.remember("assistant", response, tool_call_id) + else: + response = planning_result.text_content + self.short_term_memory.remember("assistant", response) + + def _is_terminate(self): + return True if "TERMINATE" in self.short_term_memory.last_message else False def request(self, messages: List, tools: List) -> Response: ( diff --git a/pyopenagi/agents/experiment/standard/config.json b/pyopenagi/agents/experiment/standard/config.json index e69de29bb..6f4aba03a 100644 --- a/pyopenagi/agents/experiment/standard/config.json +++ b/pyopenagi/agents/experiment/standard/config.json @@ -0,0 +1,18 @@ +{ + "name": "standard_agent", + "description": [ + + ], + "tools": [ + + ], + "meta": { + "author": "example", + "version": "0.0.1", + "license": "CC0" + }, + "build": { + "entry": "agent.py", + "module": "StandardAgent" + } +} diff --git a/pyopenagi/agents/experiment/standard/memory/short_term_memory.py b/pyopenagi/agents/experiment/standard/memory/short_term_memory.py index 745aa3c79..db4be8ac8 100644 --- a/pyopenagi/agents/experiment/standard/memory/short_term_memory.py +++ b/pyopenagi/agents/experiment/standard/memory/short_term_memory.py @@ -16,5 +16,8 @@ def remember(self, role: str, content: str, tool_call_id: int = None) -> None: def recall(self): return self.messages + def last_message(self): + return self.messages[-1] + def clear(self) -> None: self.messages = [] diff --git a/pyopenagi/agents/experiment/standard/planning/planning.py b/pyopenagi/agents/experiment/standard/planning/planning.py index a699438fb..c1fad557f 100644 --- a/pyopenagi/agents/experiment/standard/planning/planning.py +++ b/pyopenagi/agents/experiment/standard/planning/planning.py @@ -1,17 +1,49 @@ from abc import ABC, abstractmethod -from typing import List, Callable +from typing import List, Callable, Optional, Any + +from pydantic.v1 import BaseModel from pyopenagi.utils.chat_template import Response +class PlanningResult(BaseModel): + text_content: Optional[str] + action_type: Optional[str] + action_param: Optional[Any] + + class Planning(ABC): @abstractmethod def __call__(self, *args, **kwargs): pass + @abstractmethod + def format_prompt(self): + pass + class DefaultPlanning(Planning): - def __call__(self, messages: List, tools: List, request_func: Callable[[List, List], Response]): - return + def __init__(self, request_func: Callable[[List, List], Response]): + self.request_func = request_func + + def __call__(self, messages: List, tools: List): + response = self.request_func(messages, tools) + + response_message = response.response_message + tool_calls = response.tool_calls + + result = PlanningResult() + result.text_content = response_message + if tool_calls: + result.action_type = "TOOL" + result.action_param = tool_calls[0] + + return result + + def format_prompt(self): + return { + "name": "normal", + "description": "Planning as normal." + } diff --git a/pyopenagi/agents/experiment/standard/prompt/__init__.py b/pyopenagi/agents/experiment/standard/prompt/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyopenagi/agents/experiment/standard/prompt/framework_prompt.py b/pyopenagi/agents/experiment/standard/prompt/framework_prompt.py new file mode 100644 index 000000000..8b8290606 --- /dev/null +++ b/pyopenagi/agents/experiment/standard/prompt/framework_prompt.py @@ -0,0 +1,30 @@ +STANDARD_PROMPT = """ + +You are a standard agent. You hava four modules: +- Action: The Planning module guides you on how to answer questions. + Please follow the instructions provided by the Planning module strictly when responding to questions. +- Memory: +- Planning: The Planning module guides you on how to answer questions. + Please follow the instructions provided by the Planning module strictly when responding to questions. +- Communication: The Communication module provides the means for you to interact with other agents. + Follow the prompts from the Communication module to communicate and collaborate with other agents. +The following will explain the functions of the modules and how to use them. + + + +{action} + + + +{planning} + + + +{memory} + + + +{communication} + + +""" diff --git a/pyopenagi/agents/experiment/standard/utils/__init__.py b/pyopenagi/agents/experiment/standard/utils/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyopenagi/agents/experiment/standard/utils/config.py b/pyopenagi/agents/experiment/standard/utils/config.py new file mode 100644 index 000000000..affb223df --- /dev/null +++ b/pyopenagi/agents/experiment/standard/utils/config.py @@ -0,0 +1,25 @@ +import json +import os +from typing import List + +from pydantic.v1 import BaseModel + + +class Config(BaseModel): + name: str + description: List + tools: List + meta: dict + build: dict + + +def load_config(): + script_path = os.path.abspath(__file__) + script_dir = os.path.dirname( + os.path.dirname(script_path) + ) + config_file = os.path.join(script_dir, "config.json") + with open(config_file, "r") as f: + data = json.load(f) + + return Config(**data) diff --git a/pyopenagi/agents/experiment/standard/utils/str_utils.py b/pyopenagi/agents/experiment/standard/utils/str_utils.py new file mode 100644 index 000000000..17663ec6d --- /dev/null +++ b/pyopenagi/agents/experiment/standard/utils/str_utils.py @@ -0,0 +1,3 @@ +def snake_to_camel(snake_str): + components = snake_str.split("_") + return "".join(x.title() for x in components) From c874469edff0d57995f6002602a2d7819445b6d5 Mon Sep 17 00:00:00 2001 From: 2020-qqtcg Date: Fri, 18 Oct 2024 21:56:19 +0800 Subject: [PATCH 17/41] fix: log mode --- aios/hooks/llm.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/aios/hooks/llm.py b/aios/hooks/llm.py index 87cfbfa91..90a0c2e01 100644 --- a/aios/hooks/llm.py +++ b/aios/hooks/llm.py @@ -139,9 +139,7 @@ def aios_starter( max_gpu_memory, eval_device, max_new_tokens, - scheduler_log_mode, - agent_log_mode, - llm_kernel_log_mode, + log_mode, use_backend ): """ @@ -153,9 +151,7 @@ def aios_starter( max_gpu_memory (str): The maximum amount of GPU memory to use. eval_device (str): The device to evaluate the LLM on. max_new_tokens (int): The maximum number of new tokens to generate. - scheduler_log_mode (str): The log mode for the scheduler. - agent_log_mode (str): The log mode for the agents. - llm_kernel_log_mode (str): The log mode for the LLM kernel. + log_mode (str): The log mode. use_backend (str): The backend to use for running the LLM kernel. Yields: @@ -168,15 +164,15 @@ def aios_starter( max_gpu_memory=max_gpu_memory, eval_device=eval_device, max_new_tokens=max_new_tokens, - log_mode=llm_kernel_log_mode, + log_mode=log_mode, use_backend=use_backend ) # run agents concurrently for maximum efficiency using a scheduler submit_agent, await_agent_execution = useFactory( - log_mode=agent_log_mode, + log_mode=log_mode, max_workers=64 ) - with fifo_scheduler(llm=llm, log_mode=scheduler_log_mode, get_queue_message=None): + with fifo_scheduler(llm=llm, log_mode=log_mode, get_queue_message=None): yield submit_agent, await_agent_execution From 6c91e8ccaf072246f2b95f3ef8d468b59cceed98 Mon Sep 17 00:00:00 2001 From: Balaji R Date: Tue, 22 Oct 2024 14:18:13 -0400 Subject: [PATCH 18/41] Agent UI v1.5 (#6) --- agenthub/app/agentchat/page.tsx | 204 +++ agenthub/app/layout.tsx | 28 +- agenthub/components/agentchat/Header.tsx | 31 + agenthub/components/agentchat/Markdown.tsx | 122 ++ .../components/agentchat/MessageBubble.tsx | 43 + agenthub/components/agentchat/MessageList.tsx | 18 + agenthub/components/agentchat/Sidebar.tsx | 109 ++ agenthub/components/chat/body/markdown.tsx | 3 +- agenthub/components/chat/editor/Editor.tsx | 353 +++- .../components/chat/editor/MentionListV2.tsx | 71 + agenthub/components/chat/editor/Suggestion.ts | 93 ++ agenthub/interfaces/agentchat/index.ts | 14 + agenthub/package-lock.json | 1473 ++++++++++++++++- agenthub/package.json | 31 +- agenthub/postcss.config.mjs | 10 + agenthub/public/MentionListV2Dark.scss | 55 + agenthub/public/MentionListV2Light.scss | 53 + agenthub/styles/global-stylesheet.css | 33 + agenthub/tailwind.config.ts | 10 + 19 files changed, 2610 insertions(+), 144 deletions(-) create mode 100644 agenthub/app/agentchat/page.tsx create mode 100644 agenthub/components/agentchat/Header.tsx create mode 100644 agenthub/components/agentchat/Markdown.tsx create mode 100644 agenthub/components/agentchat/MessageBubble.tsx create mode 100644 agenthub/components/agentchat/MessageList.tsx create mode 100644 agenthub/components/agentchat/Sidebar.tsx create mode 100644 agenthub/components/chat/editor/MentionListV2.tsx create mode 100644 agenthub/components/chat/editor/Suggestion.ts create mode 100644 agenthub/interfaces/agentchat/index.ts create mode 100644 agenthub/public/MentionListV2Dark.scss create mode 100644 agenthub/public/MentionListV2Light.scss diff --git a/agenthub/app/agentchat/page.tsx b/agenthub/app/agentchat/page.tsx new file mode 100644 index 000000000..501772f2e --- /dev/null +++ b/agenthub/app/agentchat/page.tsx @@ -0,0 +1,204 @@ +'use client' + +import React, { useState, useRef, useEffect } from 'react'; +import { ChatEditor } from '@/components/chat/editor/Editor'; +import { useMounted } from '@/lib/mounted'; + +import { Message, Chat } from '@/interfaces/agentchat'; +import { Sidebar } from '@/components/agentchat/Sidebar'; +import { Header } from '@/components/agentchat/Header'; +import { MessageList } from '@/components/agentchat/MessageList'; +import axios from 'axios'; +import { AgentCommand } from '@/components/chat/body/message-box'; +import { baseUrl, serverUrl } from '@/lib/env'; + + + +const updateChatName = (chatId: number, newName: string) => { + // setChats(prevChats => + // prevChats.map(chat => + // chat.id === chatId ? { ...chat, name: newName } : chat + // ) + // ); +}; + + + + + + + + +const ChatInterface: React.FC = () => { + const [messages, setMessages] = useState([]); + const [darkMode, setDarkMode] = useState(false); + const [chats, setChats] = useState([{ id: 1, name: 'General' }]); + const [activeChat, setActiveChat] = useState(1); + const messagesEndRef = useRef(null); + + function parseText(input: string): string { + // Step 1: Replace mention spans with the custom format + let parsed = input.replace(/@[^<]+<\/span>/g, '?>>$1/?>>'); + + // Step 2: Convert
tags to newlines + parsed = parsed.replace(/]*>/g, '\n'); + + // Step 3: Remove all remaining HTML tags + parsed = parsed.replace(/<[^>]+>/g, ''); + + // Decode HTML entities (e.g., ", &) + parsed = parsed.replace(/"/g, '"') + .replace(/&/g, '&') + .replace(/</g, '<') + .replace(/>/g, '>') + .replace(/'/g, "'"); + + return parsed.trim(); + } + + interface MessageBundle { + name: string; + content: string; + } + + + function parseNamedContent(inputString: string) { + // Regular expression to match the pattern ?>>Name/?>>\s*Content + const regex = /\?>>(.*?)\/?>>([^?]*)/g; + const results = []; + + // Find all matches + let match; + while ((match = regex.exec(inputString)) !== null) { + // Extract name and content, trim whitespace + const name = match[1].trim().slice(0, -2); + // Preserve newlines in content but trim surrounding whitespace + const content = match[2].replace(/^\s+|\s+$/g, ''); + + results.push({ + name, + content + }); + } + + return results; + } + + // Ex + + + useEffect(() => { + messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); + }, [messages]); + + const handleSend = async (content: string, attachments: File[]) => { + if (content.trim() || attachments.length > 0) { + const newMessage: Message = { + id: Date.now(), + text: content, + sender: 'user', + timestamp: new Date(), + attachments: attachments.map(file => file.name), + thinking: false + }; + setMessages([...messages, newMessage]); + + let messageId = Date.now(); + + // Handle file uploads here (e.g., to a server) + const botMessage: Message = { + id: messageId, + text: ``, + sender: 'bot', + timestamp: new Date(), + thinking: true + }; + + setMessages(prevMessages => [...prevMessages, botMessage]); + + const res = await _(parseNamedContent(parseText(content))[0] as AgentCommand) + + setMessages(prevMessages => [...prevMessages].map(message => { + if (message.id == messageId) { + return { ...message, thinking: false }; + } + return res.content; + })); + } + }; + + const addChat = () => { + const newChat: Chat = { id: Date.now(), name: `Chat ${chats.length + 1}` }; + setChats([...chats, newChat]); + setActiveChat(newChat.id); + }; + + const _ = async (command: AgentCommand) => { + const addAgentResponse = await axios.post(`${baseUrl}/api/proxy`, { + type: 'POST', + url: `${serverUrl}/add_agent`, + payload: { + agent_name: command.name, + task_input: command.content, + } + }); + + console.log(addAgentResponse.data); + + // Wait for 1050ms + await new Promise(resolve => setTimeout(resolve, 1050)); + + let recent_response: any; + + try { + // Second request: Execute agent + const executeAgentResponse = await axios.post(`${baseUrl}/api/proxy`, { + type: 'GET', + url: `${serverUrl}/execute_agent?pid=${addAgentResponse.data.pid}`, + }); + + console.log(executeAgentResponse.data); + recent_response = executeAgentResponse.data.response.result.content; + + if (typeof recent_response !== 'string') { + recent_response = "Agent Had Difficulty Thinking" + } + } catch (e) { + recent_response = "Agent Had Difficulty Thinking" + } + + + //return recent_response + return { + name: command.name, + content: recent_response + }; + } + + const mounted = useMounted(); + + return ( +
+ +
+
+ +
+ {mounted && } +
+ +
+
+
+ ); +}; + + +export default ChatInterface; diff --git a/agenthub/app/layout.tsx b/agenthub/app/layout.tsx index 4b435eb58..e8e8a5d3f 100644 --- a/agenthub/app/layout.tsx +++ b/agenthub/app/layout.tsx @@ -45,6 +45,9 @@ import '@/styles/google-font-Source-Sans-Pro.css' import '@/styles/google-font-IBM-Plex-Mono.css' import "./globals.css"; import "./ts.css" +import '@mantine/core/styles.css'; + +import { ColorSchemeScript, MantineProvider } from '@mantine/core'; export const metadata: Metadata = { title: 'AIOS – The future of AI Agents', @@ -72,18 +75,23 @@ export default function RootLayout({ children }: { children: React.ReactNode }) */} + + + -
-
- - {/*
*/} - {children} -
-
+ +
+
+ {/* */} + {/*
*/} + {children} +
+
+
diff --git a/agenthub/components/agentchat/Header.tsx b/agenthub/components/agentchat/Header.tsx new file mode 100644 index 000000000..0064fdd20 --- /dev/null +++ b/agenthub/components/agentchat/Header.tsx @@ -0,0 +1,31 @@ +import React from 'react'; + +import { Switch, useMantineTheme } from '@mantine/core'; +import { Sun, Moon, Hash } from 'lucide-react'; + +export interface HeaderProps { + darkMode: boolean; + setDarkMode: React.Dispatch>; +} + +export const Header: React.FC = ({ darkMode, setDarkMode }) => { + const theme = useMantineTheme(); + return ( +
+
+ +

General

+
+
+ + setDarkMode(event.currentTarget.checked)} + size="sm" + color={theme.primaryColor} + /> + +
+
+ ); + }; \ No newline at end of file diff --git a/agenthub/components/agentchat/Markdown.tsx b/agenthub/components/agentchat/Markdown.tsx new file mode 100644 index 000000000..d1239146b --- /dev/null +++ b/agenthub/components/agentchat/Markdown.tsx @@ -0,0 +1,122 @@ +'use client' + +import React, { useState, useRef, useEffect } from 'react'; + +import { ActionIcon, CopyButton } from '@mantine/core'; +import { Clipboard, Check} from 'lucide-react'; + +import ReactMarkdown from 'react-markdown'; +import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; +import { atomDark } from 'react-syntax-highlighter/dist/cjs/styles/prism'; +import rehypeRaw from 'rehype-raw'; + +// Improved Markdown component +interface MarkdownProps { + content: string; + darkMode: boolean; +} + +export const Markdown: React.FC = ({ content, darkMode }) => { + const [displayedText, setDisplayedText] = useState(''); + const animationRef = useRef(null); + const currentIndexRef = useRef(0); + + useEffect(() => { + let lastTimestamp: number | null = null; + + const streamText = (timestamp: number) => { + if (lastTimestamp === null) { + lastTimestamp = timestamp; + } + + const elapsed = timestamp - lastTimestamp; + + if (elapsed >= 30) { // Minimum 30ms between updates + if (currentIndexRef.current < content.length) { + const chunkSize = Math.floor(Math.random() * 3) + 1; + const nextChunk = content.slice(currentIndexRef.current, currentIndexRef.current + chunkSize); + + setDisplayedText(prevText => prevText + nextChunk); + currentIndexRef.current += chunkSize; + + // Determine the next delay + let delay = Math.floor(Math.random() * 50) + 30; + + if (nextChunk.includes('.') || nextChunk.includes('!') || nextChunk.includes('?')) { + delay += Math.floor(Math.random() * 300) + 200; + } else if (nextChunk.includes(',') || nextChunk.includes(';')) { + delay += Math.floor(Math.random() * 150) + 100; + } + + if (nextChunk.length > 5) { + delay += nextChunk.length * 10; + } + + lastTimestamp = timestamp + delay; + } + } + + animationRef.current = requestAnimationFrame(streamText); + }; + + animationRef.current = requestAnimationFrame(streamText); + + return () => { + if (animationRef.current !== null) { + cancelAnimationFrame(animationRef.current); + } + }; + }, [content]); + + + return ( + + {children} + + ) : ( +
+
+ {match ? match[1] : 'text'} + + {({ copied, copy }) => ( + + {copied ? : } + + )} + +
+ + {String(children).replace(/\n$/, '')} + +
+ ); + }, + p: ({ children, ...props }) =>

{children}

, + br: ({ ...props }) =>
, + ul: ({ children }) =>
    {children}
, + ol: ({ children }) =>
    {children}
, + li: ({ children }) =>
  • {children}
  • , + h1: ({ children }) =>

    {children}

    , + h2: ({ children }) =>

    {children}

    , + h3: ({ children }) =>

    {children}

    , + blockquote: ({ children }) => ( +
    {children}
    + ), + }} + > + {displayedText} +
    + ); +}; \ No newline at end of file diff --git a/agenthub/components/agentchat/MessageBubble.tsx b/agenthub/components/agentchat/MessageBubble.tsx new file mode 100644 index 000000000..8cd2856f4 --- /dev/null +++ b/agenthub/components/agentchat/MessageBubble.tsx @@ -0,0 +1,43 @@ +import { Message } from "@/interfaces/agentchat"; +import { Loader } from "@mantine/core"; +import { Markdown } from "./Markdown"; + +export interface MessageBubbleProps { + message: Message; + darkMode: boolean; + index: number; + isThinking?: boolean; +} + +const AgentLoader = () => { + return
    + + Agent is thinking... +
    +} + +// Updated MessageBubble component +export const MessageBubble: React.FC = ({ message, darkMode, index, isThinking = false }) => ( +
    +
    + {message.sender === 'user' ? 'U' : 'B'} +
    +
    +
    + + {message.sender === 'user' ? 'User' : 'Bot'} + + + {message.timestamp.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })} + +
    +
    + {isThinking ? : } +
    +
    +
    + ); \ No newline at end of file diff --git a/agenthub/components/agentchat/MessageList.tsx b/agenthub/components/agentchat/MessageList.tsx new file mode 100644 index 000000000..0eb6bf8ac --- /dev/null +++ b/agenthub/components/agentchat/MessageList.tsx @@ -0,0 +1,18 @@ +import { Message } from "@/interfaces/agentchat"; +import { MessageBubble } from "./MessageBubble"; + +export interface MessageListProps { + messages: Message[]; + darkMode: boolean; +} + + +export const MessageList: React.FC = ({ messages, darkMode }) => ( +
    +
    + {messages.map((message, index) => ( + + ))} +
    +
    + ); \ No newline at end of file diff --git a/agenthub/components/agentchat/Sidebar.tsx b/agenthub/components/agentchat/Sidebar.tsx new file mode 100644 index 000000000..9f19ff8fc --- /dev/null +++ b/agenthub/components/agentchat/Sidebar.tsx @@ -0,0 +1,109 @@ +import React, { useState } from 'react'; + +import { TextInput, ActionIcon, Tooltip } from '@mantine/core'; +import { Plus, Hash, Check, Edit2, X } from 'lucide-react'; +import { Chat } from '@/interfaces/agentchat'; + + +export interface SidebarProps { + chats: Chat[]; + activeChat: number; + setActiveChat: (id: number) => void; + addChat: () => void; + updateChatName: (chatId: number, newName: string) => void; + darkMode: boolean; +} + +export const Sidebar: React.FC = ({ chats, activeChat, setActiveChat, addChat, updateChatName, darkMode }) => { + const [editingId, setEditingId] = useState(null); + const [editingName, setEditingName] = useState(''); + + const categoryStyle = "text-xs font-semibold uppercase tracking-wide text-gray-500 mb-2 mt-4 px-2 flex justify-between items-center"; + const channelStyle = `flex items-center justify-between rounded px-2 py-1.5 text-sm font-medium transition-colors duration-200 ease-in-out cursor-pointer`; + const activeChannelStyle = darkMode ? 'bg-gray-700 text-white' : 'bg-gray-300 text-gray-900'; + const inactiveChannelStyle = darkMode ? 'text-gray-400 hover:bg-gray-700 hover:text-gray-200' : 'text-gray-700 hover:bg-gray-200 hover:text-gray-900'; + + const startEditing = (chat: Chat) => { + setEditingId(chat.id); + setEditingName(chat.name); + }; + + const cancelEditing = () => { + setEditingId(null); + setEditingName(''); + }; + + const saveEditing = () => { + if (editingId !== null && editingName.trim() !== '') { + updateChatName(editingId, editingName.trim()); + setEditingId(null); + } + }; + + return ( +
    +
    +

    Your Workspace

    +
    + +
    +
    + Channels + + + + + +
    + {chats.map((chat) => ( +
    + {editingId === chat.id ? ( +
    + + setEditingName(e.target.value)} + className="flex-grow" + size="xs" + autoFocus + onKeyPress={(e) => e.key === 'Enter' && saveEditing()} + /> + + + + + + +
    + ) : ( + <> +
    setActiveChat(chat.id)}> + + {chat.name} +
    + + startEditing(chat)} + variant="subtle" + color={darkMode ? "gray" : "dark"} + className="opacity-0 group-hover:opacity-100 transition-opacity duration-200" + > + + + + + )} +
    + ))} +
    +
    + ); + }; diff --git a/agenthub/components/chat/body/markdown.tsx b/agenthub/components/chat/body/markdown.tsx index d7a72bb6d..e5a508639 100644 --- a/agenthub/components/chat/body/markdown.tsx +++ b/agenthub/components/chat/body/markdown.tsx @@ -78,7 +78,7 @@ export default function Markdown({ content }: IProps) { return match ? (
    -
    +
    {match[1]}
    {String(children).replace(/\n$/, '')} diff --git a/agenthub/components/chat/editor/Editor.tsx b/agenthub/components/chat/editor/Editor.tsx index f5643294e..0bc5128e2 100644 --- a/agenthub/components/chat/editor/Editor.tsx +++ b/agenthub/components/chat/editor/Editor.tsx @@ -1,102 +1,273 @@ 'use client' -import Document from "@tiptap/extension-document"; -import Mention from "@tiptap/extension-mention"; -import Paragraph from "@tiptap/extension-paragraph"; -import Placeholder from "@tiptap/extension-placeholder" -import Text from "@tiptap/extension-text"; -import { EditorContent, ReactRenderer, useEditor } from "@tiptap/react"; -import React, { useEffect, useState } from "react"; -import { MentionList } from "./MentionList"; -// import StarterKit from '@tiptap/starter-kit' -import dynamic from "next/dynamic"; - -export interface EditorProps { - callback: (s: string) => void +import React, { useCallback, useState, useEffect, useRef } from 'react'; +import { useEditor, EditorContent } from '@tiptap/react'; +import Document from '@tiptap/extension-document'; +import Paragraph from '@tiptap/extension-paragraph'; +import Text from '@tiptap/extension-text'; +import HardBreak from '@tiptap/extension-hard-break'; +import Placeholder from '@tiptap/extension-placeholder'; +import Mention from '@tiptap/extension-mention' +import { ActionIcon, Group, Paper, Text as MantineText, useMantineTheme, ScrollArea, Image, Box, Overlay } from '@mantine/core'; +import { Send, Plus, X, FileIcon } from 'lucide-react'; + +import suggestion from './Suggestion' +import { baseUrl, serverUrl } from '@/lib/env'; +import axios from 'axios'; + +export interface ChatEditorProps { + onSend: (content: string, attachments: File[]) => void; + darkMode: boolean; } -export const Editor: React.FC = ({ - callback -}) => { - const handleChange = (s: string) => { - console.log('handling', s) - callback(s); + + +export const ChatEditor: React.FC = ({ onSend, darkMode }) => { + const [attachments, setAttachments] = useState([]); + const [previews, setPreviews] = useState([]); + const [hoverIndex, setHoverIndex] = useState(null); + const fileInputRef = useRef(null); + const theme = useMantineTheme(); + const [agents, setAgents] = useState([]); + + useEffect(() => { + + + const _ = async () => { + const response = await axios.post(`${baseUrl}/api/proxy`, { + type: 'GET', + url: `${serverUrl}/get_all_agents`, + }); + setAgents(response.data.agents) + } + _() + }, []) + + let currentStyleElement: HTMLStyleElement | null = null; + + const loadStyle = async (isDarkMode: boolean) => { + // Remove the current style element if it exists + if (currentStyleElement && currentStyleElement.parentNode) { + currentStyleElement.parentNode.removeChild(currentStyleElement); } - const editor = useEditor({ - editorProps: { attributes: { class: "editor" } }, - immediatelyRender: false, - extensions: [ - Document, - Paragraph.configure({ - HTMLAttributes: { class: "paragraph" } - }), - Text, - // StarterKit, - Mention.configure({ - HTMLAttributes: { class: "mentionNode" }, - suggestion: { - render: () => { - //@ts-ignore - let reactRenderer: ReactRenderer; - - return { - onStart: (props: any) => { - reactRenderer = new ReactRenderer(MentionList, { - props, - editor: props.editor - }); - }, - - onUpdate(props: any) { - reactRenderer?.updateProps(props); - }, - - onKeyDown(props: any) { - if (props.event.key === "Escape") { - reactRenderer?.destroy(); - return true; - } - - return (reactRenderer?.ref as any)?.onKeyDown(props); - }, - - onExit() { - reactRenderer.destroy(); - } - }; - } - } - }), - Placeholder.configure({ - // Use a placeholder: - placeholder: '@ an agent to talk to AIOS...', - - // Use different placeholders depending on the node type: - // placeholder: ({ node }) => { - // if (node.type.name === 'heading') { - // return 'What’s the title?' - // } - - // return 'Can you add some further context?' - // }, - }), - ], - onUpdate: ({ editor }) => { - handleChange(editor.getText()); - }, - }); + const fetchStyle = async (isDarkMode: boolean) => { + const response = await fetch(isDarkMode ? '/MentionListV2Dark.scss' : '/MentionListV2Light.scss'); + return await response.text(); + }; + + // Import the new style + const style = await fetchStyle(isDarkMode) - const [isMounted, setIsMounted] = useState(false) + // Create a new style element + currentStyleElement = document.createElement('style'); + currentStyleElement.textContent = style; + document.head.appendChild(currentStyleElement); + }; - useEffect(() => { - setIsMounted(true) - }, []) + useEffect(() => { + loadStyle(darkMode); + }, [darkMode]) + - if (!isMounted) { - return null // or a loading placeholder + const editor = useEditor({ + extensions: [ + Document, + Paragraph, + Text, + HardBreak.configure({ + HTMLAttributes: { + class: 'my-2', + }, + }), + Placeholder.configure({ + placeholder: 'Type a message...', + }), + Mention.configure({ + HTMLAttributes: { + class: 'mention', + }, + suggestion, + }), + ], + editorProps: { + attributes: { + class: `focus:outline-none p-2 min-h-[40px] max-h-[300px] overflow-y-auto ${ + darkMode ? 'text-white' : 'text-gray-800' + }`, + }, + }, + }); + + const handleSend = useCallback(() => { + if (editor) { + const content = editor.getHTML(); + if (content.trim() !== '

    ' || attachments.length > 0) { + onSend(content, attachments); + editor.commands.setContent(''); + setAttachments([]); + setPreviews([]); + } + } + }, [editor, attachments, onSend]); + + const handleAttachment = useCallback((event: React.ChangeEvent) => { + const files = event.target.files; + if (files) { + const newAttachments = Array.from(files); + setAttachments(prev => [...prev, ...newAttachments]); + + newAttachments.forEach(file => { + if (file.type.startsWith('image/')) { + const reader = new FileReader(); + reader.onload = (e) => { + setPreviews(prev => [...prev, e.target?.result as string]); + }; + reader.readAsDataURL(file); + } else { + setPreviews(prev => [...prev, '']); + } + }); } + }, []); + + const removeAttachment = useCallback((index: number) => { + setAttachments(prev => prev.filter((_, i) => i !== index)); + setPreviews(prev => prev.filter((_, i) => i !== index)); + setHoverIndex(null); // Reset hover state after removal + }, []); + + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); + handleSend(); + } + }; + + editor?.view.dom.addEventListener('keydown', handleKeyDown); + + return () => { + editor?.view.dom.removeEventListener('keydown', handleKeyDown); + }; + }, [editor, handleSend]); + + const openFileInput = () => { + fileInputRef.current?.click(); + }; - return ; - // return
    -}; + return ( + + {attachments.length > 0 && ( + + + {attachments.map((file, index) => ( + setHoverIndex(index)} + onMouseLeave={() => setHoverIndex(null)} + > + {previews[index] ? ( + {file.name} + ) : ( +
    + + + {file.name} + +
    + )} + {hoverIndex === index && ( + + { + console.log('hi') + e.stopPropagation(); // Prevent event bubbling + removeAttachment(index); + }} + > + + + + )} +
    + ))} +
    +
    + )} +
    + + + + + + + + 0 ? theme.colors[theme.primaryColor][6] : 'transparent', + color: (editor && editor.getText().trim() !== '') || attachments.length > 0 ? 'white' : theme.colors.gray[5], + boxShadow: (editor && editor.getText().trim() !== '') || attachments.length > 0 ? '0 2px 4px rgba(0,0,0,0.2)' : 'none', + }} + > + + +
    +
    + ); +}; \ No newline at end of file diff --git a/agenthub/components/chat/editor/MentionListV2.tsx b/agenthub/components/chat/editor/MentionListV2.tsx new file mode 100644 index 000000000..a19a5cef7 --- /dev/null +++ b/agenthub/components/chat/editor/MentionListV2.tsx @@ -0,0 +1,71 @@ +import React, { + forwardRef, useEffect, useImperativeHandle, + useState, +} from 'react' + +export default forwardRef((props: any, ref: any) => { + const [selectedIndex, setSelectedIndex] = useState(0) + + const selectItem = (index: any) => { + const item = props.items[index] + + if (item) { + props.command({ id: item }) + } + } + + const upHandler = () => { + setSelectedIndex((selectedIndex + props.items.length - 1) % props.items.length) + } + + const downHandler = () => { + setSelectedIndex((selectedIndex + 1) % props.items.length) + } + + const enterHandler = (e: any) => { + e.stopImmediatePropagation(); + e.preventDefault(); + e.stopPropagation(); + selectItem(selectedIndex) + } + + useEffect(() => setSelectedIndex(0), [props.items]) + + useImperativeHandle(ref, () => ({ + onKeyDown: ({ event }: {event: any}) => { + if (event.key === 'ArrowUp') { + upHandler() + return true + } + + if (event.key === 'ArrowDown') { + downHandler() + return true + } + + if (event.key === 'Enter') { + enterHandler(event) + return true + } + + return false + }, + })) + + return ( +
    + {props.items.length + ? props.items.map((item: any, index: any) => ( + + )) + :
    No result
    + } +
    + ) +}) \ No newline at end of file diff --git a/agenthub/components/chat/editor/Suggestion.ts b/agenthub/components/chat/editor/Suggestion.ts new file mode 100644 index 000000000..a58f43208 --- /dev/null +++ b/agenthub/components/chat/editor/Suggestion.ts @@ -0,0 +1,93 @@ +import { ReactRenderer } from '@tiptap/react' +import tippy from 'tippy.js' + +import MentionListV2 from './MentionListV2' + +export default { + items: ({ query }: {query: any}) => { + return [ + 'Lea Thompson', + 'Cyndi Lauper', + 'Tom Cruise', + 'Madonna', + 'Jerry Hall', + 'Joan Collins', + 'Winona Ryder', + 'Christina Applegate', + 'Alyssa Milano', + 'Molly Ringwald', + 'Ally Sheedy', + 'Debbie Harry', + 'Olivia Newton-John', + 'Elton John', + 'Michael J. Fox', + 'Axl Rose', + 'Emilio Estevez', + 'Ralph Macchio', + 'Rob Lowe', + 'Jennifer Grey', + 'Mickey Rourke', + 'John Cusack', + 'Matthew Broderick', + 'Justine Bateman', + 'Lisa Bonet', + ] + .filter(item => item.toLowerCase().startsWith(query.toLowerCase())) + .slice(0, 5) + }, + + render: () => { + let component: any + let popup: any + + return { + onStart: (props: any) => { + component = new ReactRenderer(MentionListV2, { + props, + editor: props.editor, + }) + + if (!props.clientRect) { + return + } + + popup = tippy('body', { + getReferenceClientRect: props.clientRect, + appendTo: () => document.body, + content: component.element, + showOnCreate: true, + interactive: true, + trigger: 'manual', + placement: 'bottom-start', + }) + }, + + onUpdate(props: any) { + component.updateProps(props) + + if (!props.clientRect) { + return + } + + popup[0].setProps({ + getReferenceClientRect: props.clientRect, + }) + }, + + onKeyDown(props: any) { + if (props.event.key === 'Escape') { + popup[0].hide() + + return true + } + + return component.ref?.onKeyDown(props) + }, + + onExit() { + popup[0].destroy() + component.destroy() + }, + } + }, +} \ No newline at end of file diff --git a/agenthub/interfaces/agentchat/index.ts b/agenthub/interfaces/agentchat/index.ts new file mode 100644 index 000000000..7ddfe72a2 --- /dev/null +++ b/agenthub/interfaces/agentchat/index.ts @@ -0,0 +1,14 @@ +export interface Message { + thinking: boolean | undefined; + id: number; + text: string; + sender: 'user' | 'bot'; + timestamp: Date; + attachments?: string[]; // Array of file names or URLs +} + +export interface Chat { + id: number; + name: string; +} + diff --git a/agenthub/package-lock.json b/agenthub/package-lock.json index 88b803897..c1b3b123a 100644 --- a/agenthub/package-lock.json +++ b/agenthub/package-lock.json @@ -9,6 +9,19 @@ "version": "0.1.0", "hasInstallScript": true, "dependencies": { + "@mantine/carousel": "^7.13.2", + "@mantine/charts": "^7.13.2", + "@mantine/code-highlight": "^7.13.2", + "@mantine/core": "^7.13.2", + "@mantine/dates": "^7.13.2", + "@mantine/dropzone": "^7.13.2", + "@mantine/form": "^7.13.2", + "@mantine/hooks": "^7.13.2", + "@mantine/modals": "^7.13.2", + "@mantine/notifications": "^7.13.2", + "@mantine/nprogress": "^7.13.2", + "@mantine/spotlight": "^7.13.2", + "@mantine/tiptap": "^7.13.2", "@nextui-org/react": "^2.4.8", "@prisma/client": "^5.19.1", "@radix-ui/react-avatar": "^1.1.0", @@ -16,18 +29,22 @@ "@radix-ui/react-popover": "^1.1.1", "@radix-ui/react-scroll-area": "^1.1.0", "@tiptap/extension-document": "^2.7.2", + "@tiptap/extension-link": "^2.8.0", "@tiptap/extension-mention": "^2.7.2", "@tiptap/extension-paragraph": "^2.7.2", "@tiptap/extension-placeholder": "^2.7.4", "@tiptap/extension-text": "^2.7.2", - "@tiptap/pm": "^2.2.4", - "@tiptap/react": "^2.7.2", - "@tiptap/suggestion": "^2.7.2", + "@tiptap/pm": "^2.8.0", + "@tiptap/react": "^2.8.0", + "@tiptap/starter-kit": "^2.8.0", + "@tiptap/suggestion": "^2.8.0", "axios": "^1.7.7", "class-variance-authority": "^0.7.0", "classnames": "^2.5.1", "common": "^0.2.5", "copy-to-clipboard": "^3.3.3", + "dayjs": "^1.11.13", + "embla-carousel-react": "^7.1.0", "framer-motion": "^11.5.5", "install": "^0.13.0", "lodash": "^4.17.21", @@ -44,8 +61,12 @@ "react-quill-patched": "^3.0.4", "react-syntax-highlighter": "^15.5.0", "react-tooltip": "^5.28.0", + "recharts": "^2.12.7", + "rehype-raw": "^7.0.0", + "sass": "^1.80.3", "sonner": "^1.5.0", "supabase": "^1.192.5", + "tippy.js": "^6.3.7", "ui": "*" }, "devDependencies": { @@ -55,7 +76,9 @@ "@types/react-syntax-highlighter": "^15.5.13", "eslint": "^8", "eslint-config-next": "14.2.8", - "postcss": "^8", + "postcss": "^8.4.47", + "postcss-preset-mantine": "^1.17.0", + "postcss-simple-vars": "^7.0.1", "tailwindcss": "^3.4.1", "typescript": "^5" } @@ -155,6 +178,20 @@ "@floating-ui/utils": "^0.2.8" } }, + "node_modules/@floating-ui/react": { + "version": "0.26.24", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.24.tgz", + "integrity": "sha512-2ly0pCkZIGEQUq5H8bBK0XJmc1xIK/RM3tvVzY3GBER7IOD1UgmC2Y2tjj4AuS+TC+vTE1KJv2053290jua0Sw==", + "dependencies": { + "@floating-ui/react-dom": "^2.1.2", + "@floating-ui/utils": "^0.2.8", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/@floating-ui/react-dom": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz", @@ -379,6 +416,230 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@mantine/carousel": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/@mantine/carousel/-/carousel-7.13.2.tgz", + "integrity": "sha512-qFIM32uWiiQQPkdAOeymVstwOGiPR/0jxvniHO3llPB193ZFWsKKq3IBIch6zRG2bSPOV18yZsWR6VVkXYXb+A==", + "peerDependencies": { + "@mantine/core": "7.13.2", + "@mantine/hooks": "7.13.2", + "embla-carousel-react": ">=7.0.0", + "react": "^18.2.0", + "react-dom": "^18.2.0" + } + }, + "node_modules/@mantine/charts": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/@mantine/charts/-/charts-7.13.2.tgz", + "integrity": "sha512-rfaf45F58Cx5k7X9qN5yV2ZhVFAIB8i+1S/DvNE3uUflGmrevHuuNbNDDbYtQOw8ObL959rtSWOyL1SmC11D0A==", + "peerDependencies": { + "@mantine/core": "7.13.2", + "@mantine/hooks": "7.13.2", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "recharts": "^2.10.3" + } + }, + "node_modules/@mantine/code-highlight": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/@mantine/code-highlight/-/code-highlight-7.13.2.tgz", + "integrity": "sha512-gBZvsECENELXsAeCuk86/vpOnxqdOXx9e6iNbQKyiGxcmcHli0+OgnZLL4WP4xt0pd6jTni+B+kJP2g9WfJQtA==", + "dependencies": { + "clsx": "^2.1.1", + "highlight.js": "^11.9.0" + }, + "peerDependencies": { + "@mantine/core": "7.13.2", + "@mantine/hooks": "7.13.2", + "react": "^18.2.0", + "react-dom": "^18.2.0" + } + }, + "node_modules/@mantine/code-highlight/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@mantine/code-highlight/node_modules/highlight.js": { + "version": "11.10.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.10.0.tgz", + "integrity": "sha512-SYVnVFswQER+zu1laSya563s+F8VDGt7o35d4utbamowvUNLLMovFqwCLSocpZTz3MgaSRA1IbqRWZv97dtErQ==", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@mantine/core": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/@mantine/core/-/core-7.13.2.tgz", + "integrity": "sha512-nD8oKIal+KdthqF074+ZG21035QBEAKso2zK9D6zWxRTLVCjLCNSc5JSXrXLrdBTnvPQGY26yunX4+MEPlmrHg==", + "dependencies": { + "@floating-ui/react": "^0.26.9", + "clsx": "^2.1.1", + "react-number-format": "^5.3.1", + "react-remove-scroll": "^2.5.7", + "react-textarea-autosize": "8.5.3", + "type-fest": "^4.12.0" + }, + "peerDependencies": { + "@mantine/hooks": "7.13.2", + "react": "^18.2.0", + "react-dom": "^18.2.0" + } + }, + "node_modules/@mantine/core/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@mantine/core/node_modules/type-fest": { + "version": "4.26.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.26.1.tgz", + "integrity": "sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@mantine/dates": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/@mantine/dates/-/dates-7.13.2.tgz", + "integrity": "sha512-FSLGTM5s47mmHnIudRxrMXjE1EO56Qp01nATa9OwqVgVYVxxJ5xvS1ys5yxSGSE1jQk+3kyYQXHyLFcqbFhIVA==", + "dependencies": { + "clsx": "^2.1.1" + }, + "peerDependencies": { + "@mantine/core": "7.13.2", + "@mantine/hooks": "7.13.2", + "dayjs": ">=1.0.0", + "react": "^18.2.0", + "react-dom": "^18.2.0" + } + }, + "node_modules/@mantine/dates/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@mantine/dropzone": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/@mantine/dropzone/-/dropzone-7.13.2.tgz", + "integrity": "sha512-Sce2mkZ2Y2LNAIrHy6P2woRHlUiUx1tIN7yhtHt3Iils8sGH+cDERc+C53ZxKcVlEge6AlhfX0PhtancYxzDaQ==", + "dependencies": { + "react-dropzone-esm": "15.0.1" + }, + "peerDependencies": { + "@mantine/core": "7.13.2", + "@mantine/hooks": "7.13.2", + "react": "^18.2.0", + "react-dom": "^18.2.0" + } + }, + "node_modules/@mantine/form": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/@mantine/form/-/form-7.13.2.tgz", + "integrity": "sha512-jx7st64CzzzwdKwhRw/rHqQ/ReGa5tW9PnId5sdE5fhf9QJjjiNWfQjGUFnA7WSEGlOTbwrznKA45ro5lFY6CA==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "klona": "^2.0.6" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/@mantine/hooks": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-7.13.2.tgz", + "integrity": "sha512-NKfGl2sKZw6zF//AfAFJrVDftjg7DKCn0h8rwJBIZCKi9axhwlV0Mvlqe2dep8QuM7O/uLLJSymSKIv1gaxIJg==", + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/@mantine/modals": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/@mantine/modals/-/modals-7.13.2.tgz", + "integrity": "sha512-rKkXss1ZYAbkSi9ZcUsBY/HyGjgKk+bT8TXzLoClBRgg6uyto+/2lT9M5e4Nao+2PsjsRnWI/ZgddNZKiSaNgQ==", + "peerDependencies": { + "@mantine/core": "7.13.2", + "@mantine/hooks": "7.13.2", + "react": "^18.2.0", + "react-dom": "^18.2.0" + } + }, + "node_modules/@mantine/notifications": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/@mantine/notifications/-/notifications-7.13.2.tgz", + "integrity": "sha512-14vFJtR0wjO8Won96UMLxIGmKetR0ocBxcghtuGh6+wnXt6r/ezfQKsdGkkNj6w91I+0Nl9jspcxEekE5q2tBQ==", + "dependencies": { + "@mantine/store": "7.13.2", + "react-transition-group": "4.4.5" + }, + "peerDependencies": { + "@mantine/core": "7.13.2", + "@mantine/hooks": "7.13.2", + "react": "^18.2.0", + "react-dom": "^18.2.0" + } + }, + "node_modules/@mantine/nprogress": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/@mantine/nprogress/-/nprogress-7.13.2.tgz", + "integrity": "sha512-GiseMDc1K42vZa2nHS19rvvtOZX+o2vmwhVhOFRZJ8NxIaR/pk2DcRjeq2cbRFgz9/KtUZNoehOwDqHY+ZYw/A==", + "dependencies": { + "@mantine/store": "7.13.2" + }, + "peerDependencies": { + "@mantine/core": "7.13.2", + "@mantine/hooks": "7.13.2", + "react": "^18.2.0", + "react-dom": "^18.2.0" + } + }, + "node_modules/@mantine/spotlight": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/@mantine/spotlight/-/spotlight-7.13.2.tgz", + "integrity": "sha512-n8MapJHAJOCjrny4Yiy/SwAZOsa27X/JCGZ4rNwugvduliTa0WLT1KxjSg6Ne7Ys5iu4BlE5KEL6t3/LYDMI6g==", + "dependencies": { + "@mantine/store": "7.13.2" + }, + "peerDependencies": { + "@mantine/core": "7.13.2", + "@mantine/hooks": "7.13.2", + "react": "^18.2.0", + "react-dom": "^18.2.0" + } + }, + "node_modules/@mantine/store": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/@mantine/store/-/store-7.13.2.tgz", + "integrity": "sha512-JcBGOqRynYiRWzw1rYdmViB/lfeYSec2EXVdSt4eJv+RPICsjjuqrIc3sNzfqJEGxcN4hGSlaeBriSh05K+vNQ==", + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/@mantine/tiptap": { + "version": "7.13.2", + "resolved": "https://registry.npmjs.org/@mantine/tiptap/-/tiptap-7.13.2.tgz", + "integrity": "sha512-7trWaaGoyLdYdxmiunuAANL/euYjZAv5ZfVq7T/T+5SrvLObrEJicdT62nTmEoI5a7bG4R0lE7v22n4FNydohA==", + "peerDependencies": { + "@mantine/core": "7.13.2", + "@mantine/hooks": "7.13.2", + "@tiptap/extension-link": ">=2.1.12", + "@tiptap/react": ">=2.1.12", + "react": "^18.2.0", + "react-dom": "^18.2.0" + } + }, "node_modules/@next/env": { "version": "14.2.13", "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.13.tgz", @@ -1889,7 +2150,267 @@ "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", "dev": true, "engines": { - "node": ">=12.4.0" + "node": ">=12.4.0" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.4.1.tgz", + "integrity": "sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA==", + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.4.1", + "@parcel/watcher-darwin-arm64": "2.4.1", + "@parcel/watcher-darwin-x64": "2.4.1", + "@parcel/watcher-freebsd-x64": "2.4.1", + "@parcel/watcher-linux-arm-glibc": "2.4.1", + "@parcel/watcher-linux-arm64-glibc": "2.4.1", + "@parcel/watcher-linux-arm64-musl": "2.4.1", + "@parcel/watcher-linux-x64-glibc": "2.4.1", + "@parcel/watcher-linux-x64-musl": "2.4.1", + "@parcel/watcher-win32-arm64": "2.4.1", + "@parcel/watcher-win32-ia32": "2.4.1", + "@parcel/watcher-win32-x64": "2.4.1" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.4.1.tgz", + "integrity": "sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.4.1.tgz", + "integrity": "sha512-ln41eihm5YXIY043vBrrHfn94SIBlqOWmoROhsMVTSXGh0QahKGy77tfEywQ7v3NywyxBBkGIfrWRHm0hsKtzA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.4.1.tgz", + "integrity": "sha512-yrw81BRLjjtHyDu7J61oPuSoeYWR3lDElcPGJyOvIXmor6DEo7/G2u1o7I38cwlcoBHQFULqF6nesIX3tsEXMg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.4.1.tgz", + "integrity": "sha512-TJa3Pex/gX3CWIx/Co8k+ykNdDCLx+TuZj3f3h7eOjgpdKM+Mnix37RYsYU4LHhiYJz3DK5nFCCra81p6g050w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.4.1.tgz", + "integrity": "sha512-4rVYDlsMEYfa537BRXxJ5UF4ddNwnr2/1O4MHM5PjI9cvV2qymvhwZSFgXqbS8YoTk5i/JR0L0JDs69BUn45YA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.4.1.tgz", + "integrity": "sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.4.1.tgz", + "integrity": "sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.4.1.tgz", + "integrity": "sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.4.1.tgz", + "integrity": "sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.4.1.tgz", + "integrity": "sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.4.1.tgz", + "integrity": "sha512-maNRit5QQV2kgHFSYwftmPBxiuK5u4DXjbXx7q6eKjq5dsLXZ4FJiVvlcw35QXzk0KrUecJmuVFbj4uV9oYrcw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.4.1.tgz", + "integrity": "sha512-+DvS92F9ezicfswqrvIRM2njcYJbd5mb9CUgtrHCHmvn7pPPa+nMDRu1o1bYYz/l5IB2NVGNJWiH7h1E58IF2A==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, "node_modules/@pkgjs/parseargs": { @@ -4245,10 +4766,9 @@ } }, "node_modules/@tiptap/core": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.7.2.tgz", - "integrity": "sha512-rGAH90LPMR5OIG7vuTDRw8WxDYxPXSxuGtu++mxPF+Bv7V2ijPOy3P1oyV1G3KGoS0pPiNugLh+tVLsElcx/9Q==", - "peer": true, + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.8.0.tgz", + "integrity": "sha512-xsqDI4BNzYRWRtBq7+/38ThhqEr7uG9Njip1x+9/wgR3vWPBFnBkYJTz6jSxS35NRE6BSnERm4/B/vrLuY1Hdw==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" @@ -4257,10 +4777,34 @@ "@tiptap/pm": "^2.7.0" } }, + "node_modules/@tiptap/extension-blockquote": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-2.8.0.tgz", + "integrity": "sha512-m3CKrOIvV7fY1Ak2gYf5LkKiz6AHxHpg6wxfVaJvdBqXgLyVtHo552N+A4oSHOSRbB4AG9EBQ2NeBM8cdEQ4MA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-bold": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-2.8.0.tgz", + "integrity": "sha512-U1YkZBxDkSLNvPNiqxB5g42IeJHr27C7zDb/yGQN2xL4UBeg4O9xVhCFfe32f6tLwivSL0dar4ScElpaCJuqow==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, "node_modules/@tiptap/extension-bubble-menu": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.7.2.tgz", - "integrity": "sha512-U4LjkVDrJZEfWeZai8AYT7GaI6d7gzLm7Z7bSzZ0sH5fOry2qkwLycRDI9YZlM95yaVIVB5GE93lrgDS5mOP3A==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.8.0.tgz", + "integrity": "sha512-swg+myJPN60LduQvLMF4hVBqP5LOIN01INZBzBI8egz8QufqtSyRCgXl7Xcma0RT5xIXnZSG9XOqNFf2rtkjKA==", "dependencies": { "tippy.js": "^6.3.7" }, @@ -4273,10 +4817,49 @@ "@tiptap/pm": "^2.7.0" } }, + "node_modules/@tiptap/extension-bullet-list": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.8.0.tgz", + "integrity": "sha512-H4O2X0ozbc/ce9/XF1H98sqWVUdtt7jzy7hMBunwmY8ZxI4dHtcRkeg81CZbpKTqOqRrMCLWjE3M2tgiDXrDkA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/extension-list-item": "^2.7.0", + "@tiptap/extension-text-style": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-code": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-2.8.0.tgz", + "integrity": "sha512-VSFn3sFF6qPpOGkXFhik8oYRH5iByVJpFEFd/duIEftmS0MdPzkbSItOpN3mc9xsJ5dCX80LYaResSj5hr5zkA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-code-block": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-2.8.0.tgz", + "integrity": "sha512-POuA5Igx+Dto0DTazoBFAQTj/M/FCdkqRVD9Uhsxhv49swPyANTJRr05vgbgtHB+NDDsZfCawVh7pI0IAD/O0w==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, "node_modules/@tiptap/extension-document": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.7.2.tgz", - "integrity": "sha512-WyMGytHhb3MbNhJ8kUXTx/jHZ9XPaaPRJu1TYdVZNQ4pg7K47qLJ2KMOyLEFy7e5HcJUkYfhRHpyQGHkiu3brg==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.8.0.tgz", + "integrity": "sha512-mp7Isx1sVc/ifeW4uW/PexGQ9exN3NRUOebSpnLfqXeWYk4y1RS1PA/3+IHkOPVetbnapgPjFx/DswlCP3XLjA==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" @@ -4285,10 +4868,23 @@ "@tiptap/core": "^2.7.0" } }, + "node_modules/@tiptap/extension-dropcursor": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-2.8.0.tgz", + "integrity": "sha512-rAFvx44YuT6dtS1c+ALw0ROAGI16l5L1HxquL4hR1gtxDcTieST5xhw5bkshXlmrlfotZXPrhokzqA7qjhZtJw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, "node_modules/@tiptap/extension-floating-menu": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.7.2.tgz", - "integrity": "sha512-1z/kluQUQP3JmWb7vrC/ERi79lNuQegU6WRptRgSSQhFxeDPQX9CBK3I7HYy9bvSxnIa1/3GrKzL6gfaKU8WDA==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.8.0.tgz", + "integrity": "sha512-H4QT61CrkLqisnGGC7zgiYmsl2jXPHl89yQCbdlkQN7aw11H7PltcJS2PJguL0OrRVJS/Mv/VTTUiMslmsEV5g==", "dependencies": { "tippy.js": "^6.3.7" }, @@ -4301,6 +4897,109 @@ "@tiptap/pm": "^2.7.0" } }, + "node_modules/@tiptap/extension-gapcursor": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.8.0.tgz", + "integrity": "sha512-Be1LWCmvteQInOnNVN+HTqc1XWsj1bCl+Q7et8qqNjtGtTaCbdCp8ppcH1SKJxNTM/RLUtPyJ8FDgOTj51ixCA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-hard-break": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.8.0.tgz", + "integrity": "sha512-vqiIfviNiCmy/pJTHuDSCAGL2O4QDEdDmAvGJu8oRmElUrnlg8DbJUfKvn6DWQHNSQwRb+LDrwWlzAYj1K9u6A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-heading": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-2.8.0.tgz", + "integrity": "sha512-4inWgrTPiqlivPmEHFOM5ck2UsmOsbKKPtqga6bALvWPmCv24S6/EBwFp8Jz4YABabXDnkviihmGu0LpP9D69w==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-history": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.8.0.tgz", + "integrity": "sha512-u5YS0J5Egsxt8TUWMMAC3QhPZaak+IzQeyHch4gtqxftx96tprItY7AD/A3pGDF2uCSnN+SZrk6yVexm6EncDw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-horizontal-rule": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.8.0.tgz", + "integrity": "sha512-Sn/MI8WVFBoIYSIHA9NJryJIyCEzZdRysau8pC5TFnfifre0QV1ksPz2bgF+DyCD69ozQiRdBBHDEwKe47ZbfQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-italic": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-2.8.0.tgz", + "integrity": "sha512-PwwSE2LTYiHI47NJnsfhBmPiLE8IXZYqaSoNPU6flPrk1KxEzqvRI1joKZBmD9wuqzmHJ93VFIeZcC+kfwi8ZA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-link": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-link/-/extension-link-2.8.0.tgz", + "integrity": "sha512-p67hCG/pYCiOK/oCTPZnlkw9Ei7KJ7kCKFaluTcAmr5j8IBdYfDqSMDNCT4vGXBvKFh4X6xD7S7QvOqcH0Gn9A==", + "dependencies": { + "linkifyjs": "^4.1.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-list-item": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.8.0.tgz", + "integrity": "sha512-o7OGymGxB0B9x3x2prp3KBDYFuBYGc5sW69O672jk8G52DqhzzndgPnkk0qUn8nXAUKuDGbJmpmHVA2kagqnRg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, "node_modules/@tiptap/extension-mention": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/@tiptap/extension-mention/-/extension-mention-2.7.2.tgz", @@ -4315,10 +5014,24 @@ "@tiptap/suggestion": "^2.7.0" } }, + "node_modules/@tiptap/extension-ordered-list": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.8.0.tgz", + "integrity": "sha512-sCvNbcTS1+5QTTXwUPFa10vf5I1pr8sGcOTIh0G+a5ZkS5+6FxT12k7VLzPt39QyNbOi+77U2o4Xr4XyaEkfSg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/extension-list-item": "^2.7.0", + "@tiptap/extension-text-style": "^2.7.0" + } + }, "node_modules/@tiptap/extension-paragraph": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.7.2.tgz", - "integrity": "sha512-yMzUGNojNv0lLEE+38GOpgRI327EyEZK/uEHlyzbjAWRvqE6aZ+oEB4JUuoJXX2Ad9gwN16dGHnxL//ieTxrkQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.8.0.tgz", + "integrity": "sha512-XgxxNNbuBF48rAGwv7/s6as92/xjm/lTZIGTq9aG13ClUKFtgdel7C33SpUCcxg3cO2WkEyllXVyKUiauFZw/A==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" @@ -4340,10 +5053,35 @@ "@tiptap/pm": "^2.7.0" } }, + "node_modules/@tiptap/extension-strike": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.8.0.tgz", + "integrity": "sha512-ezkDiXxQ3ME/dDMMM7tAMkKRi6UWw7tIu+Mx7Os0z8HCGpVBk1gFhLlhEd8I5rJaPZr4tK1wtSehMA9bscFGQw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, "node_modules/@tiptap/extension-text": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.7.2.tgz", - "integrity": "sha512-VjzG7W53Lx2q8XV0rUHetVTQWDK28XTCTW3IzxYxHp2joB/k9q3xgE/5Vs+7DOLSHIKq2BmwQNyaE+XjUF5iYQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.8.0.tgz", + "integrity": "sha512-EDAdFFzWOvQfVy7j3qkKhBpOeE5thkJaBemSWfXI93/gMVc0ZCdLi24mDvNNgUHlT+RjlIoQq908jZaaxLKN2A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0" + } + }, + "node_modules/@tiptap/extension-text-style": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/extension-text-style/-/extension-text-style-2.8.0.tgz", + "integrity": "sha512-jJp0vcZ2Ty7RvIL0VU6dm1y+fTfXq1lN2GwtYzYM0ueFuESa+Qo8ticYOImyWZ3wGJGVrjn7OV9r0ReW0/NYkQ==", + "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" @@ -4353,9 +5091,9 @@ } }, "node_modules/@tiptap/pm": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.7.2.tgz", - "integrity": "sha512-RiRPlwpuE6IHDJytE0tglbFlWELOaqeyGRGv25wBTjzV1plnqC5B3U65XY/8kKuuLjdd3NpRfR68DXBafusSBg==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.8.0.tgz", + "integrity": "sha512-eMGpRooUMvKz/vOpnKKppApMSoNM325HxTdAJvTlVAmuHp5bOY5kyY1kfUlePRiVx1t1UlFcXs3kecFwkkBD3Q==", "dependencies": { "prosemirror-changeset": "^2.2.1", "prosemirror-collab": "^1.3.1", @@ -4382,12 +5120,12 @@ } }, "node_modules/@tiptap/react": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-2.7.2.tgz", - "integrity": "sha512-4d1TQMRHtqagCarty1iQIJMLYZ2YzBHBgAt4HlPeoDUI4MHZutOIdkl1UXmxZwh/d5p6a+tZGTVOV4aKXMW2Iw==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/react/-/react-2.8.0.tgz", + "integrity": "sha512-o/aSCjO5Nu4MsNpTF+N1SzYzVQvvBiclmTOZX2E6usZ8jre5zmKfXHDSZnjGSRTK6z6kw5KW8wpjRQha03f9mg==", "dependencies": { - "@tiptap/extension-bubble-menu": "^2.7.2", - "@tiptap/extension-floating-menu": "^2.7.2", + "@tiptap/extension-bubble-menu": "^2.8.0", + "@tiptap/extension-floating-menu": "^2.8.0", "@types/use-sync-external-store": "^0.0.6", "fast-deep-equal": "^3", "use-sync-external-store": "^1.2.2" @@ -4403,10 +5141,41 @@ "react-dom": "^17.0.0 || ^18.0.0" } }, + "node_modules/@tiptap/starter-kit": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-2.8.0.tgz", + "integrity": "sha512-r7UwaTrECkQoheWVZKFDqtL5tBx07x7IFT+prfgnsVlYFutGWskVVqzCDvD3BDmrg5PzeCWYZrQGlPaLib7tjg==", + "dependencies": { + "@tiptap/core": "^2.8.0", + "@tiptap/extension-blockquote": "^2.8.0", + "@tiptap/extension-bold": "^2.8.0", + "@tiptap/extension-bullet-list": "^2.8.0", + "@tiptap/extension-code": "^2.8.0", + "@tiptap/extension-code-block": "^2.8.0", + "@tiptap/extension-document": "^2.8.0", + "@tiptap/extension-dropcursor": "^2.8.0", + "@tiptap/extension-gapcursor": "^2.8.0", + "@tiptap/extension-hard-break": "^2.8.0", + "@tiptap/extension-heading": "^2.8.0", + "@tiptap/extension-history": "^2.8.0", + "@tiptap/extension-horizontal-rule": "^2.8.0", + "@tiptap/extension-italic": "^2.8.0", + "@tiptap/extension-list-item": "^2.8.0", + "@tiptap/extension-ordered-list": "^2.8.0", + "@tiptap/extension-paragraph": "^2.8.0", + "@tiptap/extension-strike": "^2.8.0", + "@tiptap/extension-text": "^2.8.0", + "@tiptap/pm": "^2.8.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + } + }, "node_modules/@tiptap/suggestion": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-2.7.2.tgz", - "integrity": "sha512-ZJMNuorzQQiKyzoisyeHgPH3kywv0cvQnyz5guZWiAtFWCUbFyB9MSLNuoijubwHWfnZMe4XiW5EqVt1dBmxBw==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-2.8.0.tgz", + "integrity": "sha512-ENBgO7a92cZa4gESb0Da5e7PKnHiz77tZr226VLqEdMcp7Lve2jb3Q2uL+cWCJxs7P1l6ZhetUmUiJg+Ee7Wjg==", "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" @@ -4416,6 +5185,60 @@ "@tiptap/pm": "^2.7.0" } }, + "node_modules/@types/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", + "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz", + "integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", + "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==" + }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -5491,6 +6314,116 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", @@ -5556,6 +6489,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==" + }, "node_modules/debug": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", @@ -5572,6 +6510,11 @@ } } }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==" + }, "node_modules/decode-named-character-reference": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", @@ -5680,6 +6623,17 @@ "node": ">=6" } }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/detect-node-es": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", @@ -5731,11 +6685,36 @@ "node": ">=6.0.0" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, + "node_modules/embla-carousel": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-7.1.0.tgz", + "integrity": "sha512-Bh8Pa8NWzgugLkf8sAGexQlBCNDFaej5BXiKgQdRJ1mUC9NWBrw9Z23YVPVGkguWoz5LMjZXXFVGCobl3UPt/Q==" + }, + "node_modules/embla-carousel-react": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/embla-carousel-react/-/embla-carousel-react-7.1.0.tgz", + "integrity": "sha512-tbYRPRZSDNd2QLNqYDcArAakGIxtUbhS7tkP0dGXktXHGgcX+3ji3VrOUTOftBiujZrMV8kRxtrRUe/1soloIQ==", + "dependencies": { + "embla-carousel": "7.1.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.1 || ^18.0.0" + } + }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -6407,6 +7386,14 @@ "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==" }, + "node_modules/fast-equals": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.0.1.tgz", + "integrity": "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -6971,6 +7958,53 @@ "node": ">= 0.4" } }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.1.tgz", + "integrity": "sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^8.0.0", + "property-information": "^6.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-parse5/node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-parse5/node_modules/hastscript": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-8.0.0.tgz", + "integrity": "sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/hast-util-parse-selector": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", @@ -6980,6 +8014,30 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-raw": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.0.4.tgz", + "integrity": "sha512-LHE65TD2YiNsHD3YuXcKPHXPLuYh/gjp12mOfU8jxSrm1f/yJpsb0F/KKljS6U9LJoP0Ux+tCe8iJ2AsPzTdgA==", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/hast-util-to-jsx-runtime": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.0.tgz", @@ -7006,6 +8064,24 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-to-parse5": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz", + "integrity": "sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/hast-util-whitespace": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", @@ -7094,6 +8170,15 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/https-proxy-agent": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", @@ -7115,6 +8200,11 @@ "node": ">= 4" } }, + "node_modules/immutable": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", + "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==" + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -7183,6 +8273,14 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, "node_modules/intl-messageformat": { "version": "10.5.14", "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.5.14.tgz", @@ -7767,6 +8865,14 @@ "json-buffer": "3.0.1" } }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "engines": { + "node": ">= 8" + } + }, "node_modules/language-subtag-registry": { "version": "0.3.23", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", @@ -7819,6 +8925,11 @@ "uc.micro": "^2.0.0" } }, + "node_modules/linkifyjs": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.1.3.tgz", + "integrity": "sha512-auMesunaJ8yfkHvK4gfg1K0SaKX/6Wn9g2Aac/NwX+l5VdmFZzo/hdPGxEOETj+ryRa4/fiOPjeeKURSAJx1sg==" + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -8753,6 +9864,11 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==" + }, "node_modules/node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -11373,6 +12489,17 @@ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==" }, + "node_modules/parse5": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.0.tgz", + "integrity": "sha512-ZkDsAOcxsUMZ4Lz5fVciOehNcJ+Gb8gTzcA4yl3wnc273BAybYWrQ+Ks/OjCjSEpjvQkDSeZbybK9qj2VHHdGA==", + "dependencies": { + "entities": "^4.5.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -11575,6 +12702,28 @@ "url": "https://github.com/sponsors/antonk52" } }, + "node_modules/postcss-mixins": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/postcss-mixins/-/postcss-mixins-9.0.4.tgz", + "integrity": "sha512-XVq5jwQJDRu5M1XGkdpgASqLk37OqkH4JCFDXl/Dn7janOJjCTEKL+36cnRVy7bMtoBzALfO7bV7nTIsFnUWLA==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.11", + "postcss-js": "^4.0.0", + "postcss-simple-vars": "^7.0.0", + "sugarss": "^4.0.1" + }, + "engines": { + "node": ">=14.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, "node_modules/postcss-nested": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", @@ -11599,6 +12748,19 @@ "postcss": "^8.2.14" } }, + "node_modules/postcss-preset-mantine": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/postcss-preset-mantine/-/postcss-preset-mantine-1.17.0.tgz", + "integrity": "sha512-ji1PMDBUf2Vsx/HE5faMSs1+ff6qE6YRulTr4Ja+6HD3gop8rSMTCYdpN7KrdsEg079kfBKkO/PaKhG9uR0zwQ==", + "dev": true, + "dependencies": { + "postcss-mixins": "^9.0.4", + "postcss-nested": "^6.0.1" + }, + "peerDependencies": { + "postcss": ">=8.0.0" + } + }, "node_modules/postcss-selector-parser": { "version": "6.1.2", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", @@ -11611,6 +12773,22 @@ "node": ">=4" } }, + "node_modules/postcss-simple-vars": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-simple-vars/-/postcss-simple-vars-7.0.1.tgz", + "integrity": "sha512-5GLLXaS8qmzHMOjVxqkk1TZPf1jMqesiI7qLhnlyERalG0sMbHIbJqrcnrpmZdKCLglHnRHoEBB61RtGTsj++A==", + "dev": true, + "engines": { + "node": ">=14.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.1" + } + }, "node_modules/postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", @@ -11655,7 +12833,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -11946,6 +13123,20 @@ "react": "^18.3.1" } }, + "node_modules/react-dropzone-esm": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/react-dropzone-esm/-/react-dropzone-esm-15.0.1.tgz", + "integrity": "sha512-RdeGpqwHnoV/IlDFpQji7t7pTtlC2O1i/Br0LWkRZ9hYtLyce814S71h5NolnCZXsIN5wrZId6+8eQj2EBnEzg==", + "dependencies": { + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "react": ">= 16.8 || 18.0.0" + } + }, "node_modules/react-fast-compare": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", @@ -11954,8 +13145,7 @@ "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/react-markdown": { "version": "9.0.1", @@ -11982,6 +13172,15 @@ "react": ">=18" } }, + "node_modules/react-number-format": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/react-number-format/-/react-number-format-5.4.2.tgz", + "integrity": "sha512-cg//jVdS49PYDgmcYoBnMMHl4XNTMuV723ZnHD2aXYtWWWqbVF3hjQ8iB+UZEuXapLbeA8P8H+1o6ZB1lcw3vg==", + "peerDependencies": { + "react": "^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-popper": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz", @@ -12055,6 +13254,20 @@ } } }, + "node_modules/react-smooth": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.1.tgz", + "integrity": "sha512-OE4hm7XqR0jNOq3Qmk9mFLyd6p2+j6bvbPJ7qlB7+oo0eNcL2l7WQzG6MBnT3EXY6xzkLMUBec3AfewJdA0J8w==", + "dependencies": { + "fast-equals": "^5.0.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-style-singleton": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", @@ -12121,6 +13334,21 @@ "react-dom": ">=16.14.0" } }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -12148,6 +13376,49 @@ "node": ">=8.10.0" } }, + "node_modules/recharts": { + "version": "2.12.7", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.12.7.tgz", + "integrity": "sha512-hlLJMhPQfv4/3NBSAyq3gzGg4h2v69RJh6KU7b3pXYNNAELs9kEoXOjbkxdXpALqKBoVmVptGfLpxdaVYqjmXQ==", + "dependencies": { + "clsx": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.21", + "react-is": "^16.10.2", + "react-smooth": "^4.0.0", + "recharts-scale": "^0.4.4", + "tiny-invariant": "^1.3.1", + "victory-vendor": "^36.6.8" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/recharts-scale": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "dependencies": { + "decimal.js-light": "^2.4.1" + } + }, + "node_modules/recharts/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/recharts/node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, "node_modules/reflect.getprototypeof": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", @@ -12298,6 +13569,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/remark-parse": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", @@ -12471,6 +13756,49 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/sass": { + "version": "1.80.3", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.80.3.tgz", + "integrity": "sha512-ptDWyVmDMVielpz/oWy3YP3nfs7LpJTHIJZboMVs8GEC9eUmtZTZhMHlTW98wY4aEorDfjN38+Wr/XjskFWcfA==", + "dependencies": { + "@parcel/watcher": "^2.4.1", + "chokidar": "^4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass/node_modules/chokidar": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", + "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/sass/node_modules/readdirp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", + "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/scheduler": { "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", @@ -12913,6 +14241,22 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/sugarss": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/sugarss/-/sugarss-4.0.1.tgz", + "integrity": "sha512-WCjS5NfuVJjkQzK10s8WOBY+hhDxxNt/N6ZaGwxFZ+wN3/lKKFSaaKUNecULcTTvE4urLcKaZFQD8vO0mOZujw==", + "dev": true, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.3.3" + } + }, "node_modules/supabase": { "version": "1.192.5", "resolved": "https://registry.npmjs.org/supabase/-/supabase-1.192.5.tgz", @@ -12954,6 +14298,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==" + }, "node_modules/tailwind-merge": { "version": "1.14.0", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-1.14.0.tgz", @@ -13064,6 +14413,11 @@ "node": ">=0.8" } }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==" + }, "node_modules/tippy.js": { "version": "6.3.7", "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz", @@ -13481,6 +14835,19 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/vfile-message": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", @@ -13494,6 +14861,27 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/victory-vendor": { + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, "node_modules/w3c-keyname": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", @@ -13507,6 +14895,15 @@ "loose-envify": "^1.0.0" } }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/web-streams-polyfill": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", diff --git a/agenthub/package.json b/agenthub/package.json index ca60ae627..780ad2a0e 100644 --- a/agenthub/package.json +++ b/agenthub/package.json @@ -10,6 +10,19 @@ "postinstall": "prisma generate" }, "dependencies": { + "@mantine/carousel": "^7.13.2", + "@mantine/charts": "^7.13.2", + "@mantine/code-highlight": "^7.13.2", + "@mantine/core": "^7.13.2", + "@mantine/dates": "^7.13.2", + "@mantine/dropzone": "^7.13.2", + "@mantine/form": "^7.13.2", + "@mantine/hooks": "^7.13.2", + "@mantine/modals": "^7.13.2", + "@mantine/notifications": "^7.13.2", + "@mantine/nprogress": "^7.13.2", + "@mantine/spotlight": "^7.13.2", + "@mantine/tiptap": "^7.13.2", "@nextui-org/react": "^2.4.8", "@prisma/client": "^5.19.1", "@radix-ui/react-avatar": "^1.1.0", @@ -17,18 +30,22 @@ "@radix-ui/react-popover": "^1.1.1", "@radix-ui/react-scroll-area": "^1.1.0", "@tiptap/extension-document": "^2.7.2", + "@tiptap/extension-link": "^2.8.0", "@tiptap/extension-mention": "^2.7.2", "@tiptap/extension-paragraph": "^2.7.2", "@tiptap/extension-placeholder": "^2.7.4", "@tiptap/extension-text": "^2.7.2", - "@tiptap/pm": "^2.2.4", - "@tiptap/react": "^2.7.2", - "@tiptap/suggestion": "^2.7.2", + "@tiptap/pm": "^2.8.0", + "@tiptap/react": "^2.8.0", + "@tiptap/starter-kit": "^2.8.0", + "@tiptap/suggestion": "^2.8.0", "axios": "^1.7.7", "class-variance-authority": "^0.7.0", "classnames": "^2.5.1", "common": "^0.2.5", "copy-to-clipboard": "^3.3.3", + "dayjs": "^1.11.13", + "embla-carousel-react": "^7.1.0", "framer-motion": "^11.5.5", "install": "^0.13.0", "lodash": "^4.17.21", @@ -45,8 +62,12 @@ "react-quill-patched": "^3.0.4", "react-syntax-highlighter": "^15.5.0", "react-tooltip": "^5.28.0", + "recharts": "^2.12.7", + "rehype-raw": "^7.0.0", + "sass": "^1.80.3", "sonner": "^1.5.0", "supabase": "^1.192.5", + "tippy.js": "^6.3.7", "ui": "*" }, "devDependencies": { @@ -56,7 +77,9 @@ "@types/react-syntax-highlighter": "^15.5.13", "eslint": "^8", "eslint-config-next": "14.2.8", - "postcss": "^8", + "postcss": "^8.4.47", + "postcss-preset-mantine": "^1.17.0", + "postcss-simple-vars": "^7.0.1", "tailwindcss": "^3.4.1", "typescript": "^5" } diff --git a/agenthub/postcss.config.mjs b/agenthub/postcss.config.mjs index 1a69fd2a4..af9c9825e 100644 --- a/agenthub/postcss.config.mjs +++ b/agenthub/postcss.config.mjs @@ -3,6 +3,16 @@ const config = { plugins: { tailwindcss: {}, }, + 'postcss-preset-mantine': {}, + 'postcss-simple-vars': { + variables: { + 'mantine-breakpoint-xs': '36em', + 'mantine-breakpoint-sm': '48em', + 'mantine-breakpoint-md': '62em', + 'mantine-breakpoint-lg': '75em', + 'mantine-breakpoint-xl': '88em', + }, + }, }; export default config; diff --git a/agenthub/public/MentionListV2Dark.scss b/agenthub/public/MentionListV2Dark.scss new file mode 100644 index 000000000..0f082ff40 --- /dev/null +++ b/agenthub/public/MentionListV2Dark.scss @@ -0,0 +1,55 @@ +/* Dropdown menu */ +.dropdown-menu { + background: rgb(31, 41, 55); + border: 1px solid var(--gray-4); + border-radius: 0.7rem; + box-shadow: var(--shadow); + display: flex; + flex-direction: column; + gap: 0.1rem; + overflow: auto; + padding: 0.4rem; + position: relative; + color: var(--white); + + button { + align-items: center; + background-color: transparent; + display: flex; + gap: 0.25rem; + text-align: left; + width: 100%; + + &:hover, + &:hover.is-selected { + background-color: #ccc6c631; + } + + &.is-selected { + background-color: #ccc6c631; + } + } +} + +.tiptap { + :first-child { + margin-top: 0; + } + .mention { + background-color: var(--purple-light-dark); + border-radius: 0.4rem; + box-decoration-break: clone; + color: var(--white); + // font-weight: 600; + padding: 0.1rem 0.3rem; + } +} + +.mention { + background-color: var(--purple-light-dark); + border-radius: 0.4rem; + box-decoration-break: clone; + color: var(--white); + // font-weight: 600; + padding: 0.1rem 0.3rem; +} diff --git a/agenthub/public/MentionListV2Light.scss b/agenthub/public/MentionListV2Light.scss new file mode 100644 index 000000000..9cbdf1079 --- /dev/null +++ b/agenthub/public/MentionListV2Light.scss @@ -0,0 +1,53 @@ +/* Dropdown menu */ +.dropdown-menu { + background: var(--white); + border: 1px solid var(--gray-1); + border-radius: 0.7rem; + box-shadow: var(--shadow); + display: flex; + flex-direction: column; + gap: 0.1rem; + overflow: auto; + padding: 0.4rem; + position: relative; + + button { + align-items: center; + background-color: transparent; + display: flex; + gap: 0.25rem; + text-align: left; + width: 100%; + + &:hover, + &:hover.is-selected { + background-color: var(--gray-3); + } + + &.is-selected { + background-color: var(--gray-2); + } + } + } + + .tiptap { + :first-child { + margin-top: 0; + } + + .mention { + background-color: var(--purple-light); + border-radius: 0.4rem; + box-decoration-break: clone; + color: var(--purple); + padding: 0.1rem 0.3rem; + } + } + + .mention { + background-color: var(--purple-light); + border-radius: 0.4rem; + box-decoration-break: clone; + color: var(--purple); + padding: 0.1rem 0.3rem; + } \ No newline at end of file diff --git a/agenthub/styles/global-stylesheet.css b/agenthub/styles/global-stylesheet.css index 90339a7b5..79ad28a0a 100644 --- a/agenthub/styles/global-stylesheet.css +++ b/agenthub/styles/global-stylesheet.css @@ -16891,4 +16891,37 @@ table.inference-table tr th:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; +} + +pre > .relative > .rounded-b-md { + /* Your custom styles */ + margin-top: 0px !important; + margin-left: 0px !important; + margin-right: 0px !important; + margin-bottom: 0.5em !important; + border-radius: 0 !important; + border-bottom-left-radius: 0.3em !important; + border-bottom-right-radius: 0.3em !important; +} + +:root { + --white: #FFF; + --black: #2E2B29; + --black-contrast: #110F0E; + --gray-1: rgba(61, 37, 20, .05); + --gray-2: rgba(61, 37, 20, .08); + --gray-3: rgba(61, 37, 20, .12); + --gray-4: rgba(53, 38, 28, .3); + --gray-5: rgba(28, 25, 23, .6); + --green: #22C55E; + --purple: #6A00F5; + --purple-contrast: #5800CC; + --purple-light: rgba(88, 5, 255, .05); + --purple-light-dark: rgba(88, 5, 255, .3); + --yellow-contrast: #FACC15; + --yellow: rgba(250, 204, 21, .4); + --yellow-light: #FFFAE5; + --red: #FF5C33; + --red-light: #FFEBE5; + --shadow: 0px 12px 33px 0px rgba(0, 0, 0, .06), 0px 3.618px 9.949px 0px rgba(0, 0, 0, .04) } \ No newline at end of file diff --git a/agenthub/tailwind.config.ts b/agenthub/tailwind.config.ts index 4779b4451..1df05ffb1 100644 --- a/agenthub/tailwind.config.ts +++ b/agenthub/tailwind.config.ts @@ -14,7 +14,17 @@ const config: Config = { background: "var(--background)", foreground: "var(--foreground)", }, + keyframes: { + slideIn: { + '0%': { transform: 'translateY(20px)', opacity: '0' }, + '100%': { transform: 'translateY(0)', opacity: '1' }, + } + }, + animation: { + slideIn: 'slideIn 0.3s ease-out forwards', + } }, + }, darkMode: "class", plugins: [nextui()], From bae4724f1222aacda664aa7761d55d8a26a6fd30 Mon Sep 17 00:00:00 2001 From: dongyuanjushi Date: Wed, 23 Oct 2024 21:04:03 -0400 Subject: [PATCH 19/41] update --- aios/hooks/modules/scheduler.py | 22 +++++++++++++++++----- aios/hooks/modules/storage.py | 0 aios/hooks/modules/tool.py | 0 aios/hooks/types/storage.py | 9 +++++++++ aios/hooks/types/tool.py | 9 +++++++++ 5 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 aios/hooks/modules/storage.py create mode 100644 aios/hooks/modules/tool.py create mode 100644 aios/hooks/types/storage.py create mode 100644 aios/hooks/types/tool.py diff --git a/aios/hooks/modules/scheduler.py b/aios/hooks/modules/scheduler.py index 4364c67f7..ea200ddc3 100644 --- a/aios/hooks/modules/scheduler.py +++ b/aios/hooks/modules/scheduler.py @@ -25,7 +25,7 @@ def useFIFOScheduler( params: SchedulerParams, ) -> Tuple[Callable[[], None], Callable[[], None]]: """ - Initialize and return a First-In-First-Out (FIFO) scheduler with start and stop functions. + Initialize and return a scheduler with start and stop functions. Args: params (SchedulerParams): Parameters required for the scheduler. @@ -34,16 +34,20 @@ def useFIFOScheduler( Tuple: A tuple containing the start and stop functions for the scheduler. """ if params.get_llm_request is None: - # Import a global message retrieval function if not provided from aios.hooks.stores._global import global_llm_req_queue_get_message - params.get_llm_request = global_llm_req_queue_get_message if params.get_memory_request is None: - # Import a global message retrieval function if not provided from aios.hooks.stores._global import global_memory_req_queue_get_message - params.get_memory_request = global_memory_req_queue_get_message + + if params.get_storage_request is None: + from aios.hooks.stores._global import global_storage_req_queue_get_message + params.get_storage_request = global_storage_req_queue_get_message + + if params.get_storage is None: + from aios.hooks.stores._global import global_tool_req_queue_get_message + params.get_tool_request = global_tool_req_queue_get_message scheduler = FIFOScheduler(**params.model_dump()) @@ -75,6 +79,14 @@ def fifo_scheduler(params: SchedulerParams): from aios.hooks.stores._global import global_memory_req_queue_get_message params.get_memory_request = global_memory_req_queue_get_message + if params.get_storage_request is None: + from aios.hooks.stores._global import global_storage_req_queue_get_message + params.get_storage_request = global_storage_req_queue_get_message + + if params.get_tool_request is None: + from aios.hooks.stores._global import global_tool_req_queue_get_message + params.get_tool_request = global_tool_req_queue_get_message + scheduler = FIFOScheduler(**params.model_dump()) scheduler.start() diff --git a/aios/hooks/modules/storage.py b/aios/hooks/modules/storage.py new file mode 100644 index 000000000..e69de29bb diff --git a/aios/hooks/modules/tool.py b/aios/hooks/modules/tool.py new file mode 100644 index 000000000..e69de29bb diff --git a/aios/hooks/types/storage.py b/aios/hooks/types/storage.py new file mode 100644 index 000000000..5cb8d9c6a --- /dev/null +++ b/aios/hooks/types/storage.py @@ -0,0 +1,9 @@ +from pydantic import BaseModel +from typing import Any, TypeAlias, Callable +from queue import Queue + +StorageRequestQueue: TypeAlias = Queue + +StorageRequestQueueGetMessage: TypeAlias = Callable[[], None] +StorageRequestQueueAddMessage: TypeAlias = Callable[[str], None] +StorageRequestQueueCheckEmpty: TypeAlias = Callable[[], bool] \ No newline at end of file diff --git a/aios/hooks/types/tool.py b/aios/hooks/types/tool.py new file mode 100644 index 000000000..96bfb9586 --- /dev/null +++ b/aios/hooks/types/tool.py @@ -0,0 +1,9 @@ +from pydantic import BaseModel +from typing import Any, TypeAlias, Callable +from queue import Queue + +ToolRequestQueue: TypeAlias = Queue + +ToolRequestQueueGetMessage: TypeAlias = Callable[[], None] +ToolRequestQueueAddMessage: TypeAlias = Callable[[str], None] +ToolRequestQueueCheckEmpty: TypeAlias = Callable[[], bool] \ No newline at end of file From 5b4839eea29e043c3f52578f62b10984c671ee85 Mon Sep 17 00:00:00 2001 From: 2020-qqtcg Date: Thu, 24 Oct 2024 19:54:52 +0800 Subject: [PATCH 20/41] fix: standard agent --- .../standard/communication/communication.py | 0 .../experiment/standard/memory/memory.py | 2 ++ standard_main.py | 30 +++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 pyopenagi/agents/experiment/standard/communication/communication.py create mode 100644 pyopenagi/agents/experiment/standard/memory/memory.py create mode 100644 standard_main.py diff --git a/pyopenagi/agents/experiment/standard/communication/communication.py b/pyopenagi/agents/experiment/standard/communication/communication.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyopenagi/agents/experiment/standard/memory/memory.py b/pyopenagi/agents/experiment/standard/memory/memory.py new file mode 100644 index 000000000..9469f855b --- /dev/null +++ b/pyopenagi/agents/experiment/standard/memory/memory.py @@ -0,0 +1,2 @@ +class MemoryStandard: + ... diff --git a/standard_main.py b/standard_main.py new file mode 100644 index 000000000..4aab0d7cb --- /dev/null +++ b/standard_main.py @@ -0,0 +1,30 @@ +import os +from aios.hooks.llm import aios_starter +from aios.utils.utils import parse_global_args + + +def main(**kargs): + main_id = os.getpid() + print(f"Main ID is: {main_id}") + + with aios_starter(**kargs) as (submit_agent, await_agent_execution): + + agent_tasks = [ + ["experiment/standard", "Where is China?"] + ] + + agent_ids = [] + for agent_name, task_input in agent_tasks: + agent_id = submit_agent(agent_name=agent_name, task_input=task_input) + agent_ids.append(agent_id) + + for agent_id in agent_ids: + result = await_agent_execution(agent_id) + print(f"Agent_id: {agent_id} Result: {result}") + + +if __name__ == '__main__': + parser = parse_global_args() + args = parser.parse_args() + + main(**vars(args)) From f1c01dfeebea0f9230858201451645fbcba80cf8 Mon Sep 17 00:00:00 2001 From: dongyuanjushi Date: Wed, 30 Oct 2024 08:25:51 -0400 Subject: [PATCH 21/41] add experiments --- agenthub/app/agents/const.ts | 3 +- agenthub/app/agents/type.ts | 2 +- aios/hooks/modules/memory.py | 15 +- aios/hooks/modules/storage.py | 55 ++ aios/hooks/modules/tool.py | 71 ++ aios/hooks/starter.py | 2 + aios/hooks/stores/_global.py | 18 + aios/hooks/types/scheduler.py | 6 +- aios/hooks/types/tool.py | 6 +- aios/scheduler/fifo_scheduler.py | 77 +- aios/scheduler/rr_scheduler.py | 199 +++++- aios/sdk/autogen/client_adapter.py | 4 +- aios/tool/base.py | 39 ++ experiment/__init__.py | 0 experiment/agent/__init__.py | 0 experiment/agent/autogen.py | 184 +++++ experiment/agent/experiment_agent.py | 29 + experiment/agent/interpreter.py | 111 +++ experiment/agent/metagpt.py | 18 + experiment/experiment_core.py | 65 ++ experiment/gaia/README.md | 12 + experiment/gaia/__init__.py | 0 experiment/gaia/bash_with_aios.sh | 8 + experiment/gaia/inference.py | 67 ++ experiment/gaia/run_evaluation.py | 50 ++ experiment/humaneval/README.md | 12 + experiment/humaneval/__init__.py | 0 experiment/humaneval/autogen_prediction.jsonl | 164 +++++ experiment/humaneval/bash_with_aios.sh | 8 + experiment/humaneval/convert.py | 12 + experiment/humaneval/inference.py | 82 +++ .../humaneval/interpreter_prediction.json | 658 ++++++++++++++++++ .../humaneval/interpreter_prediction.jsonl | 164 +++++ experiment/humaneval/sample.py | 11 + experiment/humaneval/samples.jsonl | 164 +++++ experiment/swe_bench/README.md | 34 + experiment/swe_bench/__init__.py | 0 experiment/swe_bench/inference.py | 114 +++ experiment/swe_bench/requirements.txt | 2 + experiment/swe_bench/run_evaluation.py | 35 + experiment/swe_bench/run_with_aios.sh | 8 + experiment/utils.py | 20 + main.py | 2 +- package-lock.json | 6 + 44 files changed, 2512 insertions(+), 25 deletions(-) create mode 100644 aios/tool/base.py create mode 100644 experiment/__init__.py create mode 100644 experiment/agent/__init__.py create mode 100644 experiment/agent/autogen.py create mode 100644 experiment/agent/experiment_agent.py create mode 100644 experiment/agent/interpreter.py create mode 100644 experiment/agent/metagpt.py create mode 100644 experiment/experiment_core.py create mode 100644 experiment/gaia/README.md create mode 100644 experiment/gaia/__init__.py create mode 100644 experiment/gaia/bash_with_aios.sh create mode 100644 experiment/gaia/inference.py create mode 100644 experiment/gaia/run_evaluation.py create mode 100644 experiment/humaneval/README.md create mode 100644 experiment/humaneval/__init__.py create mode 100644 experiment/humaneval/autogen_prediction.jsonl create mode 100644 experiment/humaneval/bash_with_aios.sh create mode 100644 experiment/humaneval/convert.py create mode 100644 experiment/humaneval/inference.py create mode 100644 experiment/humaneval/interpreter_prediction.json create mode 100644 experiment/humaneval/interpreter_prediction.jsonl create mode 100644 experiment/humaneval/sample.py create mode 100644 experiment/humaneval/samples.jsonl create mode 100644 experiment/swe_bench/README.md create mode 100644 experiment/swe_bench/__init__.py create mode 100644 experiment/swe_bench/inference.py create mode 100644 experiment/swe_bench/requirements.txt create mode 100644 experiment/swe_bench/run_evaluation.py create mode 100644 experiment/swe_bench/run_with_aios.sh create mode 100644 experiment/utils.py create mode 100644 package-lock.json diff --git a/agenthub/app/agents/const.ts b/agenthub/app/agents/const.ts index dd3445796..94236aea7 100644 --- a/agenthub/app/agents/const.ts +++ b/agenthub/app/agents/const.ts @@ -25,7 +25,8 @@ export const AgentListGenerator: () => Promise = async () => { return values; } -export const DatasetsTabList: DatasetsTabItem[] = ['Tasks', 'Sizes', 'Sub-tasks', 'Languages', 'Licenses', 'Other'] +// export const DatasetsTabList: DatasetsTabItem[] = ['Tasks', 'Sizes', 'Sub-tasks', 'Languages', 'Licenses', 'Other'] +export const AgentTabList: DatasetsTabItem[] = ['Recommended', 'Writing', 'Entertainment', 'Programming'] export const DatasetOther = [ 'Trained with AutoTrain', diff --git a/agenthub/app/agents/type.ts b/agenthub/app/agents/type.ts index 1909a81bd..01860ec77 100644 --- a/agenthub/app/agents/type.ts +++ b/agenthub/app/agents/type.ts @@ -8,7 +8,7 @@ export interface DatasetItem { favorites: string } -export type DatasetsTabItem = 'Tasks' | 'Sizes' | 'Sub-tasks' | 'Languages' | 'Licenses' | 'Other' +export type AgentTabItem = 'Tasks' | 'Sizes' | 'Sub-tasks' | 'Languages' | 'Licenses' | 'Other' export interface AgentItem { diff --git a/aios/hooks/modules/memory.py b/aios/hooks/modules/memory.py index 3a61c5cab..8fe6d4175 100644 --- a/aios/hooks/modules/memory.py +++ b/aios/hooks/modules/memory.py @@ -39,4 +39,17 @@ def addMessage(message: str): def isEmpty(): return QueueStore.isEmpty(_) - return _, getMessage, addMessage, isEmpty \ No newline at end of file + return _, getMessage, addMessage, isEmpty + +# @validate(MemoryManagerParams) +def useMemoryManager(params): + """ + Initialize and return a memory instance. + + Args: + params (MemoryParams): Parameters required for Memory Manager Initialization. + + Returns: + Memory Manager: An instance of the initialized Memory Manager. + """ + return MemoryManager(**params.model_dump()) \ No newline at end of file diff --git a/aios/hooks/modules/storage.py b/aios/hooks/modules/storage.py index e69de29bb..921c1751c 100644 --- a/aios/hooks/modules/storage.py +++ b/aios/hooks/modules/storage.py @@ -0,0 +1,55 @@ +from typing import Tuple + +from aios.hooks.types.storage import ( + StorageRequestQueue, + StorageRequestQueueGetMessage, + StorageRequestQueueAddMessage, + StorageRequestQueueCheckEmpty +) +from aios.hooks.utils.validate import validate +from aios.hooks.stores import queue as QueueStore + +def useStorageRequestQueue() -> ( + Tuple[StorageRequestQueue, StorageRequestQueueGetMessage, StorageRequestQueueAddMessage, StorageRequestQueueCheckEmpty] +): + """ + Creates and returns a queue for Storage-related requests along with helper methods to manage the queue. + + Returns: + Tuple: A tuple containing the Memory request queue, get message function, add message function, and check queue empty function. + """ + # r_str = ( + # generate_random_string() + # ) # Generate a random string for queue identification + r_str = "storage" + _ = StorageRequestQueue() + + # Store the LLM request queue in QueueStore + QueueStore.REQUEST_QUEUE[r_str] = _ + + # Function to get messages from the queue + def getMessage(): + return QueueStore.getMessage(_) + + # Function to add messages to the queue + def addMessage(message: str): + return QueueStore.addMessage(_, message) + + # Function to check if the queue is empty + def isEmpty(): + return QueueStore.isEmpty(_) + + return _, getMessage, addMessage, isEmpty + +# @validate(MemoryManagerParams) +# def useMemoryManager(params: MemoryManagerParams) -> MemoryManager: +# """ +# Initialize and return a memory instance. + +# Args: +# params (MemoryParams): Parameters required for Memory Manager Initialization. + +# Returns: +# Memory Manager: An instance of the initialized Memory Manager. +# """ +# return MemoryManager(**params.model_dump()) \ No newline at end of file diff --git a/aios/hooks/modules/tool.py b/aios/hooks/modules/tool.py index e69de29bb..8435b0397 100644 --- a/aios/hooks/modules/tool.py +++ b/aios/hooks/modules/tool.py @@ -0,0 +1,71 @@ +from random import randint + +from typing import Tuple + +from aios.tool.base import ToolManager +from aios.hooks.types.tool import ( + ToolRequestQueue, + ToolRequestQueueAddMessage, + ToolRequestQueueCheckEmpty, + ToolRequestQueueGetMessage +) +from aios.hooks.utils.validate import validate +from aios.hooks.stores import queue as QueueStore, processes as ProcessStore + +# @validate(ToolManagerParams) +def useToolManager(params) -> ToolManager: + """ + Initialize and return a tool manager instance. + + Args: + params (ToolParams): Parameters required for Tool Manager Initialization. + + Returns: + Tool Manager: An instance of the initialized Tool Manager. + """ + return ToolManager(**params.model_dump()) + +def useToolRequestQueue() -> ( + Tuple[ToolRequestQueue, ToolRequestQueueGetMessage, ToolRequestQueueAddMessage, ToolRequestQueueCheckEmpty] +): + """ + Creates and returns a queue for Storage-related requests along with helper methods to manage the queue. + + Returns: + Tuple: A tuple containing the Memory request queue, get message function, add message function, and check queue empty function. + """ + # r_str = ( + # generate_random_string() + # ) # Generate a random string for queue identification + r_str = "tool" + _ = ToolRequestQueue() + + # Store the LLM request queue in QueueStore + QueueStore.REQUEST_QUEUE[r_str] = _ + + # Function to get messages from the queue + def getMessage(): + return QueueStore.getMessage(_) + + # Function to add messages to the queue + def addMessage(message: str): + return QueueStore.addMessage(_, message) + + # Function to check if the queue is empty + def isEmpty(): + return QueueStore.isEmpty(_) + + return _, getMessage, addMessage, isEmpty + +# @validate(MemoryManagerParams) +# def useMemoryManager(params: MemoryManagerParams) -> MemoryManager: +# """ +# Initialize and return a memory instance. + +# Args: +# params (MemoryParams): Parameters required for Memory Manager Initialization. + +# Returns: +# Memory Manager: An instance of the initialized Memory Manager. +# """ +# return MemoryManager(**params.model_dump()) \ No newline at end of file diff --git a/aios/hooks/starter.py b/aios/hooks/starter.py index a1731d6ca..fb7ca73fe 100644 --- a/aios/hooks/starter.py +++ b/aios/hooks/starter.py @@ -50,5 +50,7 @@ def aios_starter( log_mode=scheduler_log_mode, get_llm_request=None, get_memory_request=None, + get_storage_request=None, + get_tool_request=None ): yield submit_agent, await_agent_execution diff --git a/aios/hooks/stores/_global.py b/aios/hooks/stores/_global.py index 9f7f905ee..830ebe872 100644 --- a/aios/hooks/stores/_global.py +++ b/aios/hooks/stores/_global.py @@ -4,6 +4,10 @@ from aios.hooks.modules.memory import useMemoryRequestQueue +from aios.hooks.modules.storage import useStorageRequestQueue + +from aios.hooks.modules.tool import useToolRequestQueue + ( global_llm_req_queue, global_llm_req_queue_get_message, @@ -17,3 +21,17 @@ global_memory_req_queue_add_message, global_memory_req_queue_is_empty, ) = useMemoryRequestQueue() + +( + global_storage_req_queue, + global_storage_req_queue_get_message, + global_storage_req_queue_add_message, + global_storage_req_queue_is_empty, +) = useStorageRequestQueue() + +( + global_tool_req_queue, + global_tool_req_queue_get_message, + global_tool_req_queue_add_message, + global_tool_req_queue_is_empty +) = useToolRequestQueue() diff --git a/aios/hooks/types/scheduler.py b/aios/hooks/types/scheduler.py index 622dbe8b4..5ca67eb30 100644 --- a/aios/hooks/types/scheduler.py +++ b/aios/hooks/types/scheduler.py @@ -3,9 +3,13 @@ from .llm import LLMRequestQueueGetMessage from .memory import MemoryRequestQueueGetMessage +from .storage import StorageRequestQueueGetMessage +from .tool import ToolRequestQueueGetMessage class SchedulerParams(BaseModel): llm: Any log_mode: str get_llm_request: LLMRequestQueueGetMessage | None - get_memory_request: MemoryRequestQueueGetMessage | None \ No newline at end of file + get_memory_request: MemoryRequestQueueGetMessage | None + get_storage_request: MemoryRequestQueueGetMessage | None + get_tool_request: MemoryRequestQueueGetMessage | None \ No newline at end of file diff --git a/aios/hooks/types/tool.py b/aios/hooks/types/tool.py index 96bfb9586..18b8f725e 100644 --- a/aios/hooks/types/tool.py +++ b/aios/hooks/types/tool.py @@ -6,4 +6,8 @@ ToolRequestQueueGetMessage: TypeAlias = Callable[[], None] ToolRequestQueueAddMessage: TypeAlias = Callable[[str], None] -ToolRequestQueueCheckEmpty: TypeAlias = Callable[[], bool] \ No newline at end of file +ToolRequestQueueCheckEmpty: TypeAlias = Callable[[], bool] + +class ToolParams(BaseModel): + name: str + params: dict | None = (None,) \ No newline at end of file diff --git a/aios/scheduler/fifo_scheduler.py b/aios/scheduler/fifo_scheduler.py index d4ca0ebed..a6927003b 100644 --- a/aios/scheduler/fifo_scheduler.py +++ b/aios/scheduler/fifo_scheduler.py @@ -4,6 +4,8 @@ from aios.hooks.types.llm import LLMRequestQueueGetMessage from aios.hooks.types.memory import MemoryRequestQueueGetMessage +from aios.hooks.types.tool import ToolRequestQueueGetMessage +from aios.hooks.types.storage import StorageRequestQueueGetMessage from queue import Queue, Empty @@ -22,16 +24,23 @@ def __init__( log_mode, get_llm_request: LLMRequestQueueGetMessage, get_memory_request: MemoryRequestQueueGetMessage, + get_storage_request: StorageRequestQueueGetMessage, + get_tool_request: ToolRequestQueueGetMessage, ): self.agent_process_queue = Queue() self.get_llm_request = get_llm_request self.get_memory_request = get_memory_request + self.get_storage_request = get_storage_request + self.get_tool_request = get_tool_request self.active = False # start/stop the scheduler self.log_mode = log_mode self.logger = self.setup_logger() # self.thread = Thread(target=self.run) self.request_processors = { - "llm_request_processor": Thread(target=self.run_llm_request), + "llm_syscall_processor": Thread(target=self.run_llm_request), + "mem_syscall_processor": Thread(target=self.run_memory_request), + "sto_syscall_processor": Thread(target=self.run_storage_request), + "tool_syscall_processor": Thread(target=self.run_tool_request) # "memory_request_processor": Thread(self.run_memory_request) } self.llm = llm @@ -118,3 +127,69 @@ def run_memory_request(self): except Exception: traceback.print_exc() + + def run_storage_request(self): + while self.active: + try: + # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty + agent_request = self.get_memory_request() + + agent_request.set_status("executing") + self.logger.log( + f"{agent_request.agent_name} is executing. \n", "execute" + ) + agent_request.set_start_time(time.time()) + + response = self.storage_manager.address_request(agent_request) + agent_request.set_response(response) + + # self.llm.address_request(agent_request) + + agent_request.event.set() + agent_request.set_status("done") + agent_request.set_end_time(time.time()) + + self.logger.log( + f"Current request of {agent_request.agent_name} is done. Thread ID is {agent_request.get_pid()}\n", + "done", + ) + # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty + + except Empty: + pass + + except Exception: + traceback.print_exc() + + def run_tool_request(self): + while self.active: + try: + # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty + agent_request = self.get_memory_request() + + agent_request.set_status("executing") + self.logger.log( + f"{agent_request.agent_name} is executing. \n", "execute" + ) + agent_request.set_start_time(time.time()) + + response = self.tool_manager.address_request(agent_request) + agent_request.set_response(response) + + # self.llm.address_request(agent_request) + + agent_request.event.set() + agent_request.set_status("done") + agent_request.set_end_time(time.time()) + + self.logger.log( + f"Current request of {agent_request.agent_name} is done. Thread ID is {agent_request.get_pid()}\n", + "done", + ) + # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty + + except Empty: + pass + + except Exception: + traceback.print_exc() diff --git a/aios/scheduler/rr_scheduler.py b/aios/scheduler/rr_scheduler.py index b84bf14ef..3142b79a5 100644 --- a/aios/scheduler/rr_scheduler.py +++ b/aios/scheduler/rr_scheduler.py @@ -11,30 +11,197 @@ from ..context.simple_context import SimpleContextManager -class RRScheduler(BaseScheduler): - def __init__(self, llm, log_mode): - super().__init__(llm, log_mode) +from aios.hooks.types.llm import LLMRequestQueueGetMessage +from aios.hooks.types.memory import MemoryRequestQueueGetMessage +from aios.hooks.types.tool import ToolRequestQueueGetMessage +from aios.hooks.types.storage import StorageRequestQueueGetMessage + +from queue import Queue, Empty + +import traceback +import time +from aios.utils.logger import SchedulerLogger + +from threading import Thread + + +class RRScheduler: + def __init__( + self, + llm, + # memory_manager, + log_mode, + get_llm_request: LLMRequestQueueGetMessage, + get_memory_request: MemoryRequestQueueGetMessage, + get_storage_request: StorageRequestQueueGetMessage, + get_tool_request: ToolRequestQueueGetMessage, + ): self.agent_process_queue = Queue() + self.get_llm_request = get_llm_request + self.get_memory_request = get_memory_request + self.get_storage_request = get_storage_request + self.get_tool_request = get_tool_request + self.active = False # start/stop the scheduler + self.log_mode = log_mode + self.logger = self.setup_logger() + # self.thread = Thread(target=self.run) + self.request_processors = { + "llm_syscall_processor": Thread(target=self.run_llm_request), + "mem_syscall_processor": Thread(target=self.run_memory_request), + "sto_syscall_processor": Thread(target=self.run_storage_request), + "tool_syscall_processor": Thread(target=self.run_tool_request) + # "memory_request_processor": Thread(self.run_memory_request) + } + self.llm = llm self.time_limit = 5 self.simple_context_manager = SimpleContextManager() + # self.memory_manager = memory_manager + + def start(self): + """start the scheduler""" + self.active = True + for name, thread_value in self.request_processors.items(): + thread_value.start() + + def stop(self): + """stop the scheduler""" + self.active = False + for name, thread_value in self.request_processors.items(): + thread_value.join() + + def setup_logger(self): + logger = SchedulerLogger("Scheduler", self.log_mode) + return logger + + def run_llm_request(self): + while self.active: + try: + # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty + agent_request = self.get_llm_request() + + agent_request.set_status("executing") + self.logger.log( + f"{agent_request.agent_name} is executing. \n", "execute" + ) + agent_request.set_start_time(time.time()) + + response = self.llm.address_request(agent_request) + agent_request.set_response(response) + + # self.llm.address_request(agent_request) + + agent_request.event.set() + agent_request.set_status("done") + agent_request.set_end_time(time.time()) + + self.logger.log( + f"Current request of {agent_request.agent_name} is done. Thread ID is {agent_request.get_pid()}\n", + "done", + ) + # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty + + except Empty: + pass + + except Exception: + traceback.print_exc() + + def run_memory_request(self): + while self.active: + try: + # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty + agent_request = self.get_memory_request() - def run(self): + agent_request.set_status("executing") + self.logger.log( + f"{agent_request.agent_name} is executing. \n", "execute" + ) + agent_request.set_start_time(time.time()) + + response = self.memory_manager.address_request(agent_request) + agent_request.set_response(response) + + # self.llm.address_request(agent_request) + + agent_request.event.set() + agent_request.set_status("done") + agent_request.set_end_time(time.time()) + + self.logger.log( + f"Current request of {agent_request.agent_name} is done. Thread ID is {agent_request.get_pid()}\n", + "done", + ) + # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty + + except Empty: + pass + + except Exception: + traceback.print_exc() + + def run_storage_request(self): + while self.active: + try: + # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty + agent_request = self.get_memory_request() + + agent_request.set_status("executing") + self.logger.log( + f"{agent_request.agent_name} is executing. \n", "execute" + ) + agent_request.set_start_time(time.time()) + + response = self.storage_manager.address_request(agent_request) + agent_request.set_response(response) + + # self.llm.address_request(agent_request) + + agent_request.event.set() + agent_request.set_status("done") + agent_request.set_end_time(time.time()) + + self.logger.log( + f"Current request of {agent_request.agent_name} is done. Thread ID is {agent_request.get_pid()}\n", + "done", + ) + # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty + + except Empty: + pass + + except Exception: + traceback.print_exc() + + def run_tool_request(self): while self.active: try: - """ - wait 0.05 seconds between each iteration at the minimum - if there is nothing received in a second, it will raise Empty - """ - agent_process = self.agent_process_queue.get(block=True, timeout=0.05) - agent_process.set_time_limit(self.time_limit) + # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty + agent_request = self.get_memory_request() + + agent_request.set_status("executing") + self.logger.log( + f"{agent_request.agent_name} is executing. \n", "execute" + ) + agent_request.set_start_time(time.time()) + + response = self.tool_manager.address_request(agent_request) + agent_request.set_response(response) - agent_process.set_status("executing") - # self.logger.log(f"{agent_process.agent_name} is switched to executing.\n", level="execute") - self.execute_request(agent_process) + # self.llm.address_request(agent_request) + + agent_request.event.set() + agent_request.set_status("done") + agent_request.set_end_time(time.time()) + + self.logger.log( + f"Current request of {agent_request.agent_name} is done. Thread ID is {agent_request.get_pid()}\n", + "done", + ) + # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty except Empty: pass - def execute_request(self, agent_request): - """ called in multiple threads """ - self.llm.address_request(agent_request) + except Exception: + traceback.print_exc() + diff --git a/aios/sdk/autogen/client_adapter.py b/aios/sdk/autogen/client_adapter.py index 262e5d9fe..3f67e3305 100644 --- a/aios/sdk/autogen/client_adapter.py +++ b/aios/sdk/autogen/client_adapter.py @@ -53,8 +53,8 @@ def adapter_autogen_client_init(self, *, def adapter_client_create(self, **config: Any) -> ModelClient.ModelClientResponseProtocol: - if ERROR: - raise ERROR + # if ERROR: + # raise ERROR invocation_id = str(uuid.uuid4()) last = len(self._clients) - 1 # Check if all configs in config list are activated diff --git a/aios/tool/base.py b/aios/tool/base.py new file mode 100644 index 000000000..f82a4b933 --- /dev/null +++ b/aios/tool/base.py @@ -0,0 +1,39 @@ +import importlib + +class ToolManager: + def __init__( + self, + log_mode: str = "console", + ): + self.log_mode = log_mode + self.tool_conflict_map = {} + + def address_request(self, agent_request, temperature=0.0) -> None: + request_data = agent_request.request_data + tool_org_and_name, tool_params = request_data["name"], request_data["paramemters"] + org, tool_name = tool_org_and_name.split("/") + + if tool_name not in self.tool_conflict_map.keys(): + self.tool_conflict_map[tool_name] = 1 + tool_class = self.load_tool_instance(tool_name) + + tool = tool_class( + tool_name=tool_name + ) + tool.run( + params = tool_params + ) + + self.tool_conflict_map.pop(tool_name) + + def snake_to_camel(self, snake_str): + components = snake_str.split("_") + return "".join(x.title() for x in components) + + def load_tool_instance(self, tool_org_and_name): + org, tool_name = tool_org_and_name.split("/") + module_name = ".".join(["pyopenagi", "tools", org, tool_name]) + class_name = self.snake_to_camel(tool_name) + tool_module = importlib.import_module(module_name) + tool_instance = getattr(tool_module, class_name) + return tool_instance diff --git a/experiment/__init__.py b/experiment/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/experiment/agent/__init__.py b/experiment/agent/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/experiment/agent/autogen.py b/experiment/agent/autogen.py new file mode 100644 index 000000000..db0e8b4be --- /dev/null +++ b/experiment/agent/autogen.py @@ -0,0 +1,184 @@ +import functools +from typing import Annotated + +from autogen import ConversableAgent + +from aios.sdk import prepare_framework, FrameworkType +from experiment.agent.experiment_agent import ExpirementAgent +from pyopenagi.tools.arxiv.arxiv import Arxiv + + +class AutoGenAgent(ExpirementAgent): + _TERMINATION = "" + + def __init__(self, on_aios: bool = True): + if on_aios: + prepare_framework(FrameworkType.AutoGen) + + def run(self, input_str: str): + assistant_sender = ConversableAgent( + name="assistant_1", + system_message="Your name is assistant_1. When you think task is finished, say .", + human_input_mode="NEVER" + ) + + assistant_recipient = ConversableAgent( + name="assistant_2", + is_termination_msg=lambda msg: msg.get("content") is not None and self._TERMINATION in msg["content"], + human_input_mode="NEVER" + ) + + chat_result = assistant_sender.initiate_chat(assistant_recipient, message=input_str, max_turns=20) + + chat_history = chat_result.chat_history + for message in reversed(chat_history): + if "```patch" in message["content"]: + result = message["content"] + print(f"AutoGen result is: {result}") + return message["content"] + + return "" + + +class AutoGenAgentGAIA(ExpirementAgent): + + SYSTEM_PROMPT = """You are a general AI assistant. I will ask you a question. Report your thoughts, and finish + your answer with the following template: FINAL ANSWER: [YOUR FINAL ANSWER]. + YOUR FINAL ANSWER should be a number OR as few words as possible OR a comma separated list of + numbers and/or strings. + If you are asked for a number, don’t use comma to write your number neither use units such as $ or percent + sign unless specified otherwise. + If you are asked for a string, don’t use articles, neither abbreviations (e.g. for cities), and write the digits in + plain text unless specified otherwise. + If you are asked for a comma separated list, apply the above rules depending of whether the element to be put + in the list is a number or a string.""" + + _TERMINATION = "FINAL ANSWER" + + def __init__(self, on_aios: bool = True): + if on_aios: + prepare_framework(FrameworkType.AutoGen) + + def run(self, input_str: str): + assistant_sender = ConversableAgent( + name="User", + is_termination_msg=lambda msg: msg.get("content") is not None and self._TERMINATION in msg["content"], + human_input_mode="NEVER" + ) + + assistant_recipient = ConversableAgent( + name="Assistant", + system_message=self.SYSTEM_PROMPT, + human_input_mode="NEVER" + ) + + # register tools + for tool in TOOL_COLLECTION: + assistant_recipient.register_for_llm( + name=tool["name"], description=tool["description"] + )(tool["function"]) + + assistant_sender.register_for_execution(name=tool["name"])(tool["function"]) + + # start chat + chat_result = assistant_sender.initiate_chat(assistant_recipient, message=input_str, max_turns=20) + + chat_history = chat_result.chat_history + for message in reversed(chat_history): + if "FINAL ANSWER" in message["content"]: + result = message["content"] + print(f"AutoGen result is: {result}") + return message["content"] + + return "" + + +class AutoGenAgentHumanEval(ExpirementAgent): + + SYSTEM_PROMPT = """You are an AI assistant good at coding. You will receive a function definition and + comments. You need to help me complete this function. I will help you check your code. If you think it is ok to + give the final answer. Give me final output in the format: + + YOUR FINAL ANSWER (YOUR FINAL ANSWER must be a piece of code that you want to add. Just + contains what you add, don't contains original definition and comments) + + Don’t rush to provide the final result; you can first try asking me if the code is correct.""" + + USER_PROMPT = """You are a software engineer. You will check the code written by Assistant and help Assistant + optimize code.""" + + _TERMINATION = "" + + def __init__(self, on_aios: bool = True): + if on_aios: + prepare_framework(FrameworkType.AutoGen) + + def run(self, input_str: str): + assistant_sender = ConversableAgent( + name="User", + is_termination_msg=lambda msg: msg.get("content") is not None and self._TERMINATION in msg["content"], + human_input_mode="NEVER" + ) + + assistant_recipient = ConversableAgent( + name="Assistant", + system_message=self.SYSTEM_PROMPT, + human_input_mode="NEVER" + ) + + # start chat + chat_result = assistant_sender.initiate_chat(assistant_recipient, message=input_str, max_turns=20) + + chat_history = chat_result.chat_history + for message in reversed(chat_history): + if self._TERMINATION in message["content"]: + result = message["content"] + + print(f"AutoGen result is: {result}") + return result + + return "" + + +TOOL_COLLECTION = [] + + +def add_tool(description: str): + def add_tool_helper(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + return func(*args, **kwargs) + + func_name = func.__name__ + TOOL_COLLECTION.append({ + "name": func_name, + "description": description, + "function": func + }) + return wrapper + + return add_tool_helper + + +@add_tool(description="Query articles or topics in arxiv") +def arxiv( + query: Annotated[str, "Input query that describes what to search in arxiv"] +) -> str: + arxiv_obj = Arxiv() + + tool_param = { + "query": query, + } + return arxiv_obj.run(tool_param) + + +@add_tool(description="Search information using google search api") +def google_search( + query: Annotated[str, "Prompt description of the image to be generated"] +) -> str: + arxiv_obj = Arxiv() + + tool_param = { + "query": query, + } + return arxiv_obj.run(tool_param) diff --git a/experiment/agent/experiment_agent.py b/experiment/agent/experiment_agent.py new file mode 100644 index 000000000..e3040f590 --- /dev/null +++ b/experiment/agent/experiment_agent.py @@ -0,0 +1,29 @@ +from abc import ABC, abstractmethod + +from aios.hooks.request import send_request +from pyopenagi.utils.chat_template import Query + + +class ExpirementAgent(ABC): + + @abstractmethod + def run(self, input_str: str): + pass + + +class SimpleLLMAgent(ExpirementAgent): + + def __init__(self, on_aios: bool = True): + self.agent_name = "gpt" + self.on_aios = on_aios + + def run(self, input_str: str): + message = {"content": input_str, "role": "user"} + query = Query(messages=[message], tools=None) + + response, _, _, _, _ = send_request( + agent_name=self.agent_name, + query=query + ) + result = response.response_message + return result diff --git a/experiment/agent/interpreter.py b/experiment/agent/interpreter.py new file mode 100644 index 000000000..ed013a5a3 --- /dev/null +++ b/experiment/agent/interpreter.py @@ -0,0 +1,111 @@ +import os +import re + +from interpreter import interpreter + +from aios.sdk import prepare_framework, FrameworkType +from experiment.agent.experiment_agent import ExpirementAgent + + +class InterpreterAgent(ExpirementAgent): + + SYSTEM_PROMPT_WRITE = """\n You can try writing some code to solve the problem, but please note that you are not in the + problem repository. Must write your final patch into patch.diff. If code is hard to run, just write the patch you + think right. You should write patch.diff use Here Document, for example: + cat < patch.diff + + EOF_59812759871 \n""" + + SYSTEM_PROMPT = """\n You can try writing some code to solve the problem, but please note that you are not in the + problem repository. Finally give me a patch that can be written into git diff file, format like this: + ```patch + patch content here + ``` + """ + + def __init__(self, on_aios: bool = True): + if on_aios: + prepare_framework(FrameworkType.OpenInterpreter) + interpreter.messages = [] + interpreter.auto_run = True + self.interpreter = interpreter + + def run(self, input_str: str): + + input_str += self.SYSTEM_PROMPT + result = self.interpreter.chat(input_str) + + try: + result = result[0] if isinstance(result, list) else result + except IndexError: + return str(result) + + try: + # read model output + current_directory = os.getcwd() + diff_path = os.path.join(current_directory, "patch.diff") + + with open(diff_path, 'r') as file: + diff_content = file.read() + result_content = f"```patch {diff_content}```" + + os.remove(diff_path) + + except Exception: + result_content = result["content"] + # content_lines = result_content.split("\n") + # result_content = "\n".join(content_lines[1:-1]) + # result_content = f"```patch {result_content}```" + + print(f"Interterper result is: {result_content} \n") + return result_content + + +class InterpreterAgentHumanEval(ExpirementAgent): + + SYSTEM_PROMPT = """You will receive a function definition and comments. You need to help me complete this function. + + Give me final output in the format: + + YOUR FINAL ANSWER (YOUR FINAL ANSWER must be a piece of code that you want to add. The final result must remove + the function definition and function description provided in the problem statement, as well as any unit test + code you added.) + """ + + def __init__(self, on_aios: bool = True): + if on_aios: + prepare_framework(FrameworkType.OpenInterpreter) + interpreter.messages = [] + interpreter.auto_run = True + self.interpreter = interpreter + + def run(self, input_str: str): + input_str += self.SYSTEM_PROMPT + result = self.interpreter.chat(input_str) + + try: + result = result[0] if isinstance(result, list) else result + if isinstance(result, list): + result = result[0] + except IndexError as e: + print(f"IndexError: {e}") + return str(result) + + print(f"Interterper result is: {result} \n") + if isinstance(result, dict): + result_content = result["content"] + + if result["type"] == "code": + result_content = f""" + ```python + {result_content} + ```""" + elif result["type"] == "message": + match = re.search(r'\s*([\s\S]*?)', result_content) + if match: + result_content = match.group(1) + else: + result_content = result + + print(f"Interterper result is: {result_content} \n") + return result_content diff --git a/experiment/agent/metagpt.py b/experiment/agent/metagpt.py new file mode 100644 index 000000000..b47ec618b --- /dev/null +++ b/experiment/agent/metagpt.py @@ -0,0 +1,18 @@ +from metagpt.software_company import generate_repo, ProjectRepo + +from aios.sdk.metagpt.adapter import prepare_metagpt +from experiment.agent.experiment_agent import ExpirementAgent + + +class MetaGPTAgent(ExpirementAgent): + + def __init__(self): + prepare_metagpt() + + def run(self, input_str: str): + repo: ProjectRepo = generate_repo("\nI need you read following details, helping me solving issues by changing " + "code surrounding by ' ' block. Then write it into a new " + "python file. Result file list should contains a new.py contains the new " + "code''.Details: \n" + + input_str) + return str(repo) diff --git a/experiment/experiment_core.py b/experiment/experiment_core.py new file mode 100644 index 000000000..615c78679 --- /dev/null +++ b/experiment/experiment_core.py @@ -0,0 +1,65 @@ +from typing import Any, Callable + +from pydantic.v1 import BaseModel +from tqdm import tqdm + +from aios.utils.logger import SDKLogger +from experiment.agent.autogen import AutoGenAgent, AutoGenAgentGAIA, AutoGenAgentHumanEval +from experiment.agent.experiment_agent import SimpleLLMAgent +from experiment.agent.interpreter import InterpreterAgent, InterpreterAgentHumanEval +from experiment.agent.metagpt import MetaGPTAgent + + +AGENT_TYPE_MAPPING_AIOS = { + "swe:interpreter": InterpreterAgent, + "swe:gpt": SimpleLLMAgent, + "swe:metagpt": MetaGPTAgent, + "swe:autogen": AutoGenAgent, + "gaia:autogen": AutoGenAgentGAIA, + "humaneval:autogen": AutoGenAgentHumanEval, + "humaneval:interpreter": InterpreterAgentHumanEval, +} + +logger = SDKLogger("Experiment") + + +class MetaData(BaseModel): + dataset: Any + split: str = None + agent_type: str + output_file: str + on_aios: bool = True + max_num: int = None + aios_args: dict + + +def run(process_one_func, meta_data: MetaData, write_output_func=None): + total_result = [] + if meta_data.split: + dataset = meta_data.dataset[meta_data.split] + else: + dataset = meta_data.dataset + + for data in tqdm(dataset): + if meta_data.max_num is not None: + if meta_data.max_num > 0: + meta_data.max_num -= 1 + else: + logger.log(f"Max num {meta_data.max_num} reached", level="info") + break + + result = process_one_func(data, meta_data) + total_result.append(result) + + if write_output_func: + write_output_func(total_result, meta_data.output_file) + return total_result + + +def run_inference(meta_data: MetaData, process_one_func: Callable, write_output_func: Callable = None): + + run( + process_one_func=process_one_func, + meta_data=meta_data, + write_output_func=write_output_func, + ) diff --git a/experiment/gaia/README.md b/experiment/gaia/README.md new file mode 100644 index 000000000..ab118ef63 --- /dev/null +++ b/experiment/gaia/README.md @@ -0,0 +1,12 @@ +## run inference +```shell +python -m experiment.gaia.inference \ + --data_name gaia-benchmark/GAIA \ + --split validation \ + --output_file experiment/gaia_prediction.json \ + --on_aios \ +# --max_num 1 \ + --agent_type autogen \ + --llm_name gpt-4o-mini \ + --max_new_tokens 8000 +``` diff --git a/experiment/gaia/__init__.py b/experiment/gaia/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/experiment/gaia/bash_with_aios.sh b/experiment/gaia/bash_with_aios.sh new file mode 100644 index 000000000..7dace5c17 --- /dev/null +++ b/experiment/gaia/bash_with_aios.sh @@ -0,0 +1,8 @@ +python -m experiment.gaia.inference \ + --data_name gaia-benchmark/GAIA \ + --split validation \ + --output_file experiment/gaia_prediction.json \ + --on_aios \ + --agent_type autogen \ + --llm_name gpt-4o-mini \ + --max_new_tokens 8000 \ No newline at end of file diff --git a/experiment/gaia/inference.py b/experiment/gaia/inference.py new file mode 100644 index 000000000..367f29239 --- /dev/null +++ b/experiment/gaia/inference.py @@ -0,0 +1,67 @@ +import json +import re +from typing import List + +from datasets import load_dataset +from aios.hooks.starter import aios_starter +from experiment.agent.experiment_agent import ExpirementAgent +from experiment.experiment_core import MetaData, run_inference, AGENT_TYPE_MAPPING_AIOS, logger +from experiment.utils import get_args + + +def write_output_func(result_list: List, output_file: str): + with open(output_file, "w", encoding="utf-8") as file: + json.dump(result_list, file, ensure_ascii=False, indent=4) + logger.log(f"Write results num: {len(result_list)}", level="info") + + +def process_one_func(data, meta_data: MetaData): + if meta_data.on_aios: + with aios_starter(**meta_data.aios_args): + agent: ExpirementAgent = AGENT_TYPE_MAPPING_AIOS[meta_data.agent_type](meta_data.on_aios) + result = agent.run(data["Question"]) + + match = re.search(r'FINAL ANSWER: (.+)', result) + if match: + result = match.group(1) + + prediction = { + "task_id": data["task_id"], + "result": result, + } + return prediction + else: + agent: ExpirementAgent = AGENT_TYPE_MAPPING_AIOS[meta_data.agent_type](meta_data.on_aios) + result = agent.run(data["Question"]) + + match = re.search(r'FINAL ANSWER: (.+)', result) + if match: + result = match.group(1) + + prediction = { + "task_id": data["task_id"], + "result": result, + } + return prediction + + +if __name__ == '__main__': + main_args, global_args = get_args() + + agent_type = "gaia:" + main_args.agent_type + dataset = load_dataset(main_args.data_name, "2023_all", split=main_args.split) + + meta = MetaData( + dataset=dataset, + agent_type=agent_type, + output_file=main_args.output_file, + on_aios=main_args.on_aios, + max_num=main_args.max_num, + aios_args=vars(global_args), + ) + + run_inference( + meta_data=meta, + process_one_func=process_one_func, + write_output_func=write_output_func, + ) diff --git a/experiment/gaia/run_evaluation.py b/experiment/gaia/run_evaluation.py new file mode 100644 index 000000000..53d5c01a0 --- /dev/null +++ b/experiment/gaia/run_evaluation.py @@ -0,0 +1,50 @@ +import argparse +import json + +from datasets import load_dataset +from tqdm import tqdm + +from experiment.experiment_core import logger + + +def run_evaluation(input_file: str, output_file: str, data_name: str, split: str): + dataset = load_dataset(data_name, "2023_all", split=split) + + with open(input_file, "r", encoding="utf-8") as file: + predictions = json.load(file) + + right_num = 0 + error_predictions = [] + for prediction, data in tqdm(zip(predictions, dataset)): + if prediction["result"] == data["Final answer"]: + right_num += 1 + else: + error_predictions.append({ + "task_id": data["task_id"], + "error_answer": prediction["result"], + "right_answer": data["Final answer"], + }) + + with open(output_file, "w", encoding="utf-8") as file: + json.dump(error_predictions, file, ensure_ascii=False, indent=4) + + logger.log(f"Total num: {len(predictions)} \n" + f" Right num: {right_num} \n" + f" Right Rate: {right_num/len(predictions)}" + , level="info") + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("--input_file", type=str, default="experiment/gaia_prediction.json") + parser.add_argument("--output_file", type=str, default="experiment/gaia_evaluation.json") + parser.add_argument("--data_name", type=str, default="gaia-benchmark/GAIA") + parser.add_argument("--split", type=str, default="validation") + + args = parser.parse_args() + run_evaluation( + args.input_file, + args.output_file, + args.data_name, + args.split + ) diff --git a/experiment/humaneval/README.md b/experiment/humaneval/README.md new file mode 100644 index 000000000..6145bf405 --- /dev/null +++ b/experiment/humaneval/README.md @@ -0,0 +1,12 @@ +## run inference +```shell +python -m experiment.humaneval.inference \ + --data_name openai/openai_humaneval \ + --split test \ + --output_file experiment/humaneval_prediction.json \ + --on_aios \ +# --max_num 1 \ + --agent_type interpreter \ + --llm_name gpt-4o-mini \ + --max_new_tokens 8000 +``` diff --git a/experiment/humaneval/__init__.py b/experiment/humaneval/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/experiment/humaneval/autogen_prediction.jsonl b/experiment/humaneval/autogen_prediction.jsonl new file mode 100644 index 000000000..da008e227 --- /dev/null +++ b/experiment/humaneval/autogen_prediction.jsonl @@ -0,0 +1,164 @@ +{"task_id": "HumanEval/0", "completion": "from typing import List\n\n \"\"\" Check if in given list of numbers, are any two numbers closer to each other than\n given threshold.\n \n >>> has_close_elements([1.0, 2.0, 3.0], 0.5)\n False\n >>> has_close_elements([1.0, 2.8, 3.0, 4.0, 5.0, 2.0], 0.3)\n True\n >>> has_close_elements([1.0, 1.5, 2.0, 2.3], 0.3)\n True\n >>> has_close_elements([], 0.5)\n False\n >>> has_close_elements([1.0, 1.1, 2.5], 0.2)\n True\n \"\"\"\n n = len(numbers)\n for i in range(n):\n for j in range(i + 1, n):\n if abs(numbers[i] - numbers[j]) < threshold:\n return True\n return False\n "} +{"task_id": "HumanEval/1", "completion": "paren_string = paren_string.replace(\" \", \"\") # Remove spaces\n groups = [] # List to store separate groups\n current_group = \"\" # To build the current group of parentheses\n balance_counter = 0 # To track the balance of parentheses\n\n for char in paren_string:\n current_group += char # Build the current group\n if char == '(': # Increment for open parenthesis\n balance_counter += 1\n elif char == ')': # Decrement for close parenthesis\n balance_counter -= 1\n\n if balance_counter == 0: # Group is complete\n groups.append(current_group) # Add to the list\n current_group = \"\" # Reset for next group\n\n return groups\n "} +{"task_id": "HumanEval/2", "completion": "# Ensure the input is positive\nif number < 0:\n raise ValueError(\"The number must be positive.\")\n\n# Get the integer part of the number\nint_part = int(number)\n\n# Calculate the decimal part\ndecimal_part = number - int_part\n\nreturn decimal_part\n "} +{"task_id": "HumanEval/3", "completion": " "} +{"task_id": "HumanEval/4", "completion": "if not numbers: # Check if the list is empty\n return 0.0\n \n mean_value = sum(numbers) / len(numbers) # Step 1: Calculate the mean\n absolute_differences = [abs(x - mean_value) for x in numbers] # Step 2: Calculate absolute differences\n mad = sum(absolute_differences) / len(numbers) # Step 3: Calculate the average of the absolute differences\n \n return mad\n "} +{"task_id": "HumanEval/5", "completion": ">>> intersperse([5], 0)\n [5]\n >>> intersperse([1, 2], 3)\n [1, 3, 2]\n >>> intersperse([10, 20, 30, 40], 100)\n [10, 100, 20, 100, 30, 100, 40]\n "} +{"task_id": "HumanEval/6", "completion": " def max_depth(group: str) -> int:\n current_depth = 0\n max_depth = 0\n\n for char in group:\n if char == '(':\n current_depth += 1\n max_depth = max(max_depth, current_depth)\n elif char == ')':\n current_depth -= 1\n \n return max_depth\n\n # Split the input string into groups based on spaces\n groups = paren_string.split()\n depths = [max_depth(group) for group in groups]\n \n return depths\n "} +{"task_id": "HumanEval/7", "completion": "I'm glad the implementation met your expectations! Here\u2019s the final answer for what to add to the function:\n\n\n return [s for s in strings if substring in s]\n "} +{"task_id": "HumanEval/8", "completion": "\n total_sum = sum(numbers)\n total_product = reduce(operator.mul, numbers, 1)\n \n return (total_sum, total_product)\n "} +{"task_id": "HumanEval/9", "completion": "result = []\n current_max = float('-inf') # Initialize to negative infinity\n\n for number in numbers:\n current_max = max(current_max, number) # Update current_max\n result.append(current_max) # Append the current max to result\n\n return result\n "} +{"task_id": "HumanEval/10", "completion": "if not string or is_palindrome(string):\n return string\n \n for i in range(len(string)):\n if is_palindrome(string[i:]):\n prefix = string[:i]\n return string + prefix[::-1]\n \n return string + string[::-1]\n "} +{"task_id": "HumanEval/11", "completion": "if len(a) != len(b):\n raise ValueError(\"Input strings must be of the same length.\")\n\n result = ''.join('1' if a[i] != b[i] else '0' for i in range(len(a)))\n return result\n "} +{"task_id": "HumanEval/12", "completion": "if not strings: # Check if the list is empty\n return None\n \n longest_string = strings[0] # Start with the first string as the longest\n \n for string in strings: # Iterate through each string in the list\n if len(string) > len(longest_string): # Compare lengths\n longest_string = string # Update longest_string if a longer string is found\n \n return longest_string # Return the longest string found\n "} +{"task_id": "HumanEval/13", "completion": "while b != 0:\n a, b = b, a % b\n return abs(a) # Return the absolute value of GCD\n "} +{"task_id": "HumanEval/14", "completion": "from typing import List\n\n \"\"\" Return list of all prefixes from shortest to longest of the input string\n >>> all_prefixes('abc')\n ['a', 'ab', 'abc']\n \"\"\"\n return [string[:i] for i in range(1, len(string) + 1)]\n\n# Testing the function\nprint(all_prefixes('abc')) # Output: ['a', 'ab', 'abc']\n "} +{"task_id": "HumanEval/15", "completion": "return ' '.join(str(i) for i in range(n + 1))\n "} +{"task_id": "HumanEval/16", "completion": "return len(set(string.lower()))\n "} +{"task_id": "HumanEval/17", "completion": "# Mapping of notes to beats\n note_to_beats = {\n 'o': 4,\n 'o|': 2,\n '.|': 1\n }\n \n # Split the input string into notes\n notes = music_string.split()\n \n # Parse the notes and build the result list\n beats_list = [note_to_beats[note] for note in notes]\n \n return beats_list\n "} +{"task_id": "HumanEval/18", "completion": "\n count = 0\n start = 0\n \n while True:\n start = string.find(substring, start)\n if start == -1: # No more occurrences found\n break\n count += 1\n start += 1 # Move one character ahead for overlapping search\n \n return count\n "} +{"task_id": "HumanEval/19", "completion": "num_mapping = {\n 'zero': 0,\n 'one': 1,\n 'two': 2,\n 'three': 3,\n 'four': 4,\n 'five': 5,\n 'six': 6,\n 'seven': 7,\n 'eight': 8,\n 'nine': 9\n }\n \n rev_mapping = {v: k for k, v in num_mapping.items()}\n \n num_list = numbers.split()\n \n int_list = [num_mapping[num] for num in num_list]\n \n int_list.sort()\n \n sorted_num_list = [rev_mapping[num] for num in int_list]\n \n return ' '.join(sorted_num_list)\n "} +{"task_id": "HumanEval/20", "completion": "return closest_pair\n "} +{"task_id": "HumanEval/21", "completion": "\n min_val = min(numbers)\n max_val = max(numbers)\n \n # Handle the case where all numbers are the same\n if max_val == min_val:\n return [0.0] * len(numbers)\n \n return [(num - min_val) / (max_val - min_val) for num in numbers]\n "} +{"task_id": "HumanEval/22", "completion": "return [value for value in values if isinstance(value, int)]\n "} +{"task_id": "HumanEval/23", "completion": " "} +{"task_id": "HumanEval/24", "completion": " \"\"\"For a given number n, find the largest number that divides n evenly, smaller than n.\n \n >>> largest_divisor(15)\n 5\n >>> largest_divisor(10)\n 5\n >>> largest_divisor(1)\n 0\n >>> largest_divisor(28)\n 14\n >>> largest_divisor(20)\n 10\n >>> largest_divisor(37)\n 1\n >>> largest_divisor(100)\n 50\n \"\"\"\n for i in range(n - 1, 0, -1): # Start from n-1 down to 1\n if n % i == 0: # Check if i divides n evenly\n return i # Return the first divisor found\n return 0 # If no divisors found, return 0 (for n = 1)\n "} +{"task_id": "HumanEval/25", "completion": "factors = []\n factor = 2\n \n while n > 1:\n while n % factor == 0:\n factors.append(factor)\n n //= factor\n factor += 1\n \n if factor * factor > n:\n if n > 1:\n factors.append(n)\n break\n\n return factors\n "} +{"task_id": "HumanEval/26", "completion": "counts = {}\n for number in numbers:\n counts[number] = counts.get(number, 0) + 1\n\n result = [number for number in numbers if counts[number] == 1]\n\n return result\n "} +{"task_id": "HumanEval/27", "completion": "return string.swapcase()\n "} +{"task_id": "HumanEval/28", "completion": "\n return ''.join(strings)\n "} +{"task_id": "HumanEval/29", "completion": "return [s for s in strings if s.startswith(prefix)]\n "} +{"task_id": "HumanEval/30", "completion": "return [x for x in l if x > 0]\n "} +{"task_id": "HumanEval/31", "completion": "if n <= 1:\n return False\n if n <= 3:\n return True # 2 and 3 are prime numbers\n\n if n % 2 == 0 or n % 3 == 0:\n return False\n\n # Check for factors from 5 to the square root of n\n i = 5\n while i * i <= n:\n if n % i == 0 or n % (i + 2) == 0:\n return False\n i += 6\n\n return True\n "} +{"task_id": "HumanEval/32", "completion": " \"\"\"Calculate the derivative of the polynomial at point x.\"\"\"\n return sum([i * coeff * math.pow(x, i - 1) for i, coeff in enumerate(xs) if i > 0])\n\n \"\"\"Finds a root of the polynomial defined by coefficients xs.\"\"\"\n if len(xs) % 2 != 0:\n raise ValueError(\"Coefficient list must have an even number of elements.\")\n\n x = initial_guess\n for iteration in range(max_iterations):\n f_x = poly(xs, x)\n f_prime_x = derivative(xs, x)\n\n if f_prime_x == 0: # Avoid division by zero\n raise ValueError(\"Derivative is zero, no solution found.\")\n\n x_new = x - f_x / f_prime_x\n\n if abs(x_new - x) < tolerance: # Convergence check\n return x_new\n\n x = x_new\n\n raise ValueError(\"Maximum iterations reached, no solution found.\")\n "} +{"task_id": "HumanEval/33", "completion": "# Collect values at indices divisible by 3\n third_values = [l[i] for i in range(len(l)) if i % 3 == 0]\n \n # Sort the collected values\n third_values.sort()\n \n # Create a new list to hold the result\n result = l[:] # Make a copy of the original list\n \n # Place sorted values back in their original indices\n for idx, value in enumerate(third_values):\n result[idx * 3] = value # idx * 3 gives us the original index in l\n \n return result\n "} +{"task_id": "HumanEval/34", "completion": "Your implementation of the `unique` function looks correct! It effectively removes duplicates and sorts the elements. The provided code meets the requirements in the docstring and should work as expected.\n\nIf you want to encapsulate the addition part of the implementation succinctly for submission, here\u2019s how that would look:\n\n\n return sorted(set(l))\n "} +{"task_id": "HumanEval/35", "completion": "return max(l)\n "} +{"task_id": "HumanEval/36", "completion": "count = 0\n for i in range(n):\n if i % 11 == 0 or i % 13 == 0:\n count += str(i).count('7')\n return count\n "} +{"task_id": "HumanEval/37", "completion": "even_elements = [l[i] for i in range(0, len(l), 2)]\n even_elements.sort()\n result = []\n even_index = 0\n \n for i in range(len(l)):\n if i % 2 == 0:\n result.append(even_elements[even_index])\n even_index += 1\n else:\n result.append(l[i])\n \n return result\n "} +{"task_id": "HumanEval/38", "completion": "# Split string into groups of length 3.\n groups = [s[(3 * i):min((3 * i + 3), len(s))] for i in range((len(s) + 2) // 3)]\n # Cycle elements back for each group of three characters.\n groups = [(group[-1] + group[:-1]) if len(group) == 3 else group for group in groups]\n return \"\".join(groups)\n "} +{"task_id": "HumanEval/39", "completion": " \"\"\"Helper function to determine if a number is prime.\"\"\"\n if num <= 1:\n return False\n if num <= 3:\n return True\n if num % 2 == 0 or num % 3 == 0:\n return False\n i = 5\n while i * i <= num:\n if num % i == 0 or num % (i + 2) == 0:\n return False\n i += 6\n return True\n\n \"\"\"Generator for Fibonacci numbers.\"\"\"\n a, b = 0, 1\n while True:\n a, b = b, a + b\n yield a\n\n \"\"\"\n prime_fib returns the n-th number that is a Fibonacci number and it's also prime.\n >>> prime_fib(1)\n 2\n >>> prime_fib(2)\n 3\n >>> prime_fib(3)\n 5\n >>> prime_fib(4)\n 13\n >>> prime_fib(5)\n 89\n \"\"\"\n fib_gen = fibonacci_generator()\n count = 0\n while True:\n fib_num = next(fib_gen)\n if is_prime(fib_num):\n count += 1\n if count == n:\n return fib_num\n "} +{"task_id": "HumanEval/40", "completion": " n = len(l)\n l.sort() # Sort the list to facilitate checking pairs.\n \n for i in range(n - 2): # We need at least three numbers to check.\n if i > 0 and l[i] == l[i - 1]:\n continue\n \n left, right = i + 1, n - 1\n \n while left < right:\n current_sum = l[i] + l[left] + l[right]\n \n if current_sum == 0:\n return True\n elif current_sum < 0:\n left += 1\n else:\n right -= 1\n \n return False\n "} +{"task_id": "HumanEval/41", "completion": "return n * n\n "} +{"task_id": "HumanEval/42", "completion": "return [x + 1 for x in l]\n "} +{"task_id": "HumanEval/43", "completion": "seen = set()\n for num in l:\n if -num in seen:\n return True\n seen.add(num)\n return False\n "} +{"task_id": "HumanEval/44", "completion": "if x == 0:\n return '0' # Handling zero explicitly\n\n digits = []\n while x > 0:\n remainder = x % base # Get the remainder\n digits.append(str(remainder)) # Store the remainder as a string\n x //= base # Divide x by the base\n\n return ''.join(reversed(digits))\n "} +{"task_id": "HumanEval/45", "completion": "It sounds like you are satisfied with the function implementation and are looking to confirm it one last time. Here\u2019s the final output in the requested format:\n\n\n return 0.5 * a * h\n "} +{"task_id": "HumanEval/46", "completion": "if n == 0:\n return 0\n elif n == 1:\n return 0\n elif n == 2:\n return 2\n elif n == 3:\n return 0\n \n fib_values = [0, 0, 2, 0] # Starting values for fib4(0), fib4(1), fib4(2), fib4(3)\n\n for i in range(4, n + 1):\n next_value = fib_values[i - 1] + fib_values[i - 2] + fib_values[i - 3] + fib_values[i - 4]\n fib_values.append(next_value)\n\n return fib_values[n]\n "} +{"task_id": "HumanEval/47", "completion": "Your breakdown of the logic of the `median` function looks great, and the code implementation you provided follows that logic correctly. \n\nNow I will provide just the part that needs to be added to the original function definition based on your explanation.\n\n\n # Step 1: Sort the list\n sorted_list = sorted(l)\n\n # Step 2: Find the length of the sorted list\n n = len(sorted_list)\n\n # Step 3: Calculate the median\n if n % 2 == 1:\n # Odd length: return the middle element\n return sorted_list[n // 2]\n else:\n # Even length: return the average of the two middle elements\n mid1 = sorted_list[n // 2 - 1]\n mid2 = sorted_list[n // 2]\n return (mid1 + mid2) / 2\n "} +{"task_id": "HumanEval/48", "completion": "return text == text[::-1]\n "} +{"task_id": "HumanEval/49", "completion": "result = 1\n base = 2 % p\n while n > 0:\n if n % 2 == 1:\n result = (result * base) % p\n base = (base * base) % p\n n //= 2\n return result\n "} +{"task_id": "HumanEval/50", "completion": "return \"\".join([chr(((ord(ch) - 5 - ord(\"a\")) % 26) + ord(\"a\")) for ch in s])\n "} +{"task_id": "HumanEval/51", "completion": "vowels = 'aeiouAEIOU'\n return ''.join(char for char in text if char not in vowels)\n "} +{"task_id": "HumanEval/52", "completion": "for num in l:\n if num >= t:\n return False\n return True\n "} +{"task_id": "HumanEval/53", "completion": "return x + y\n "} +{"task_id": "HumanEval/54", "completion": "Since you confirmed the implementation is correct, here\u2019s the final addition based on your original comments and structure:\n\n\n return set(s0) == set(s1)\n "} +{"task_id": "HumanEval/55", "completion": " \"\"\"Return n-th Fibonacci number using iteration.\"\"\"\n if n == 0:\n return 0\n elif n == 1:\n return 1\n\n a, b = 0, 1\n for _ in range(2, n + 1):\n a, b = b, a + b\n return b\n "} +{"task_id": "HumanEval/56", "completion": "count = 0\n for bracket in brackets:\n if bracket == '<':\n count += 1\n elif bracket == '>':\n count -= 1\n if count < 0:\n return False\n return count == 0\n "} +{"task_id": "HumanEval/57", "completion": " \"\"\"Return True if list elements are monotonically increasing or decreasing.\n >>> monotonic([1, 2, 4, 20])\n True\n >>> monotonic([1, 20, 4, 10])\n False\n >>> monotonic([4, 1, 0, -10])\n True\n >>> monotonic([])\n True\n >>> monotonic([5])\n True\n >>> monotonic([2, 2, 2])\n True\n \"\"\"\n if len(l) <= 1: # An empty or a single element list is considered monotonically true\n return True\n\n increasing = decreasing = True\n\n for i in range(1, len(l)):\n if l[i] < l[i - 1]: # Found one pair that is decreasing\n increasing = False\n if l[i] > l[i - 1]: # Found one pair that is increasing\n decreasing = False\n\n return increasing or decreasing\n "} +{"task_id": "HumanEval/58", "completion": "set1 = set(l1)\n set2 = set(l2)\n common_elements = set1.intersection(set2)\n return sorted(common_elements)\n "} +{"task_id": "HumanEval/59", "completion": "largest_factor = None\n\n # Check for number of 2s that divide n\n while n % 2 == 0:\n largest_factor = 2\n n //= 2\n\n # Now check for odd factors from 3 to sqrt(n)\n for i in range(3, int(n**0.5) + 1, 2):\n while n % i == 0:\n largest_factor = i\n n //= i\n\n # If n is a prime number greater than 2\n if n > 2:\n largest_factor = n\n\n return largest_factor\n "} +{"task_id": "HumanEval/60", "completion": "return n * (n + 1) // 2 # Use integer division\n "} +{"task_id": "HumanEval/61", "completion": "balance = 0\n for bracket in brackets:\n if bracket == '(':\n balance += 1\n elif bracket == ')':\n balance -= 1\n if balance < 0:\n return False\n return balance == 0\n "} +{"task_id": "HumanEval/62", "completion": "return [i * xs[i] for i in range(1, len(xs))]\n "} +{"task_id": "HumanEval/63", "completion": " \"\"\"Compute the n-th FibFib number.\"\"\"\n # Base cases\n if n == 0:\n return 0\n elif n == 1:\n return 0\n elif n == 2:\n return 1\n\n # Memoization dictionary\n memo = {0: 0, 1: 0, 2: 1}\n\n def helper(k):\n if k in memo:\n return memo[k]\n # Calculate the value and store it in the memo\n memo[k] = helper(k - 1) + helper(k - 2) + helper(k - 3)\n return memo[k]\n\n return helper(n)\n "} +{"task_id": "HumanEval/64", "completion": "# Test cases\nif __name__ == \"__main__\":\n # Existing test cases\n print(vowels_count(\"abcde\")) # Expected output: 2\n print(vowels_count(\"ACEDY\")) # Expected output: 3\n \n # Additional test cases\n print(vowels_count(\"hello\")) # Expected output: 2\n print(vowels_count(\"sky\")) # Expected output: 1\n print(vowels_count(\"rhythm\")) # Expected output: 0 (y not at the end)\n print(vowels_count(\"AEIOU\")) # Expected output: 5\n print(vowels_count(\"aeiouy\")) # Expected output: 6\n print(vowels_count(\"xyz\")) # Expected output: 0\n print(vowels_count(\"\")) # Expected output: 0 (empty string)\n print(vowels_count(\"y\")) # Expected output: 1 (y at the end)\n "} +{"task_id": "HumanEval/65", "completion": "digits = str(x)\n n = len(digits)\n effective_shift = shift % n\n\n if effective_shift == 0:\n return digits[::-1] # Reverse digits if effective shift is zero.\n \n # Perform the circular shift to the right\n return digits[-effective_shift:] + digits[:-effective_shift]\n "} +{"task_id": "HumanEval/66", "completion": "The implementation you provided looks correct, and it follows the outlined requirements based on the task description and examples given. It properly sums the ASCII values of only the uppercase letters within the input string.\n\nIf you would like me to encapsulate the implementation in the appropriate output format as specified, here it is:\n\n\n return sum(ord(char) for char in s if char.isupper())\n "} +{"task_id": "HumanEval/67", "completion": "words = s.split()\n apples = int(words[0]) # The first number is apples\n oranges = int(words[3]) # The fourth word is oranges\n mangoes = n - apples - oranges\n return mangoes\n "} +{"task_id": "HumanEval/68", "completion": "smallest_even = None\n smallest_index = -1\n\n for index, value in enumerate(arr):\n if value % 2 == 0: # Check if the value is even\n if smallest_even is None or value < smallest_even:\n smallest_even = value\n smallest_index = index\n\n if smallest_even is not None:\n return [smallest_even, smallest_index]\n else:\n return []\n "} +{"task_id": "HumanEval/69", "completion": "frequency = Counter(lst)\n result = -1\n \n for number in frequency:\n if frequency[number] >= number:\n result = max(result, number)\n \n return result\n "} +{"task_id": "HumanEval/70", "completion": "if not lst:\n return []\n\nsorted_lst = sorted(lst)\n\nresult = []\nleft = 0\nright = len(sorted_lst) - 1\ntoggle = True\n\nwhile left <= right:\n if toggle:\n result.append(sorted_lst[left])\n left += 1\n else:\n result.append(sorted_lst[right])\n right -= 1\n toggle = not toggle \n\nreturn result\n "} +{"task_id": "HumanEval/71", "completion": "# Check for valid triangle using triangle inequality theorem\n if a + b > c and a + c > b and b + c > a:\n # Calculate the semi-perimeter\n s = (a + b + c) / 2\n \n # Calculate the area using Heron's formula\n area = (s * (s - a) * (s - b) * (s - c)) ** 0.5\n \n # Return the area rounded to 2 decimal points\n return round(area, 2)\n else:\n # Not a valid triangle\n return -1\n "} +{"task_id": "HumanEval/72", "completion": "is_balanced = (q == q[::-1])\n total_weight = sum(q)\n return is_balanced and total_weight <= w\n "} +{"task_id": "HumanEval/73", "completion": "To implement the `smallest_change` function, we need to compare corresponding elements from the start and end of the array, moving towards the center. For each pair of elements that are not equal, we would need to make a change for the array to be palindromic. The number of such changes will give us the result.\n\nHere's how to complete the function:\n\n1. Initialize a counter to keep track of changes needed.\n2. Loop through the array from the start to the middle (using the index range).\n3. For each index, compare the element with its corresponding element from the end of the array.\n4. If they are not equal, increment the counter.\n5. Return the counter after the loop.\n\nLet's implement this logic.\n\n\n counter = 0\n n = len(arr)\n for i in range(n // 2):\n if arr[i] != arr[n - 1 - i]:\n counter += 1\n return counter\n "} +{"task_id": "HumanEval/74", "completion": "total1 = sum(len(s) for s in lst1)\n total2 = sum(len(s) for s in lst2)\n \n if total1 < total2:\n return lst1\n elif total1 > total2:\n return lst2\n else:\n return lst1\n "} +{"task_id": "HumanEval/75", "completion": " \"\"\"Check if a number is prime.\"\"\"\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n\n \"\"\"Generate a list of prime numbers up to a given limit.\"\"\"\n return [n for n in range(2, limit) if is_prime(n)]\n\n \"\"\"Check if a number is the product of exactly three prime numbers.\"\"\"\n \n if a < 2:\n return False\n\n primes = generate_primes(100)\n \n # Check products of combinations of three primes\n from itertools import combinations\n\n for p1, p2, p3 in combinations(primes, 3):\n if p1 * p2 * p3 == a:\n return True\n\n return False\n "} +{"task_id": "HumanEval/76", "completion": " \"\"\"Returns True if x is a simple power of n (n**int = x), otherwise returns False.\"\"\"\n if n <= 1:\n return x == 1\n if x < 1:\n return False\n \n power = n\n while power < x:\n power *= n\n \n return power == x\n "} +{"task_id": "HumanEval/77", "completion": "n = round(abs(a) ** (1/3)) \n return a == n ** 3 \n "} +{"task_id": "HumanEval/78", "completion": "\n prime_digits = {'2', '3', '5', '7', 'B', 'D'}\n count = sum(1 for digit in num if digit in prime_digits)\n return count\n "} +{"task_id": "HumanEval/79", "completion": " binary_string = bin(decimal)[2:]\n return f'db{binary_string}db'\n "} +{"task_id": "HumanEval/80", "completion": "# The implementation provided is correct and complete, no further additions needed.\n "} +{"task_id": "HumanEval/81", "completion": "letter_grades = []\n for gpa in grades:\n if gpa == 4.0:\n letter_grades.append('A+')\n elif gpa > 3.7:\n letter_grades.append('A')\n elif gpa > 3.3:\n letter_grades.append('A-')\n elif gpa > 3.0:\n letter_grades.append('B+')\n elif gpa > 2.7:\n letter_grades.append('B')\n elif gpa > 2.3:\n letter_grades.append('B-')\n elif gpa > 2.0:\n letter_grades.append('C+')\n elif gpa > 1.7:\n letter_grades.append('C')\n elif gpa > 1.3:\n letter_grades.append('C-')\n elif gpa > 1.0:\n letter_grades.append('D+')\n elif gpa > 0.7:\n letter_grades.append('D')\n elif gpa > 0.0:\n letter_grades.append('D-')\n else:\n letter_grades.append('E')\n return letter_grades\n "} +{"task_id": "HumanEval/82", "completion": " \"\"\"Returns True if the length of the input string is a prime number, False otherwise.\n \n Parameters:\n string (str): The input string to evaluate.\n \n Returns:\n bool: True if the length of the string is prime, False otherwise.\n \"\"\"\n if not isinstance(string, str):\n raise ValueError(\"Input must be a string.\")\n \n length = len(string)\n return is_prime(length)\n "} +{"task_id": "HumanEval/83", "completion": "# Count of n-digit numbers that end with '1'\n end_with_1 = 10 ** (n - 1) # Any digit can follow the first digit including '0'\n \n # Count of n-digit numbers that both start and end with '1'\n start_and_end_with_1 = 10 ** (n - 2) if n > 1 else 0 # n must be at least 2 for this count\n "} +{"task_id": "HumanEval/84", "completion": "sum_of_digits = sum(int(digit) for digit in str(N))\n return bin(sum_of_digits)[2:]\n "} +{"task_id": "HumanEval/85", "completion": "total = 0 # Initialize a variable to hold the sum of the even elements at odd indices\n \n # Iterate over the list using enumerate to get both index and value\n for index, value in enumerate(lst):\n # Check if the index is odd and the value is even\n if index % 2 == 1 and value % 2 == 0:\n total += value # Add the even value at the odd index to the total\n \n return total # Return the total sum\n "} +{"task_id": "HumanEval/86", "completion": " words = s.split(' ')\n \n def sort_word(word):\n return ''.join(sorted(word))\n \n sorted_words = [sort_word(word) for word in words]\n \n return ' '.join(sorted_words)\n "} +{"task_id": "HumanEval/87", "completion": "coordinates = []\n \n for row_idx, row in enumerate(lst):\n for col_idx, value in enumerate(row):\n if value == x:\n coordinates.append((row_idx, col_idx))\n \n coordinates.sort(key=lambda coord: (coord[0], -coord[1]))\n \n return coordinates\n "} +{"task_id": "HumanEval/88", "completion": "sorted_array = array[:]\n \n if len(sorted_array) <= 1:\n return sorted_array\n \n first_value = sorted_array[0]\n last_value = sorted_array[-1]\n total_sum = first_value + last_value\n \n if total_sum % 2 == 0:\n sorted_array.sort(reverse=True)\n else:\n sorted_array.sort()\n \n return sorted_array\n "} +{"task_id": "HumanEval/89", "completion": "encrypted_string = ''\n \n for char in s:\n if 'a' <= char <= 'z': # Check if the character is a lowercase letter\n # Rotate the letter by 4 positions\n new_char = chr((ord(char) - ord('a') + 4) % 26 + ord('a'))\n encrypted_string += new_char\n else:\n # Characters that are not lowercase letters are added unchanged\n encrypted_string += char\n \n return encrypted_string\n "} +{"task_id": "HumanEval/90", "completion": " \"\"\"\n Returns the second smallest unique element from the list.\n Returns None if there is no such element.\n \"\"\"\n # Remove duplicates by converting to a set\n unique_elements = set(lst)\n \n # If there are less than 2 unique elements, return None\n if len(unique_elements) < 2:\n return None\n \n # Sort the unique elements\n sorted_unique_elements = sorted(unique_elements)\n \n # Return the second smallest element\n return sorted_unique_elements[1]\n "} +{"task_id": "HumanEval/91", "completion": "sentences = [sentence.strip() for sentence in S.replace('!', '.').replace('?', '.').split('.') if sentence]\n \n count = 0\n\n for sentence in sentences:\n if sentence.startswith(\"I\"):\n count += 1\n \n return count\n "} +{"task_id": "HumanEval/92", "completion": "# Check if all inputs are integers\n if isinstance(x, int) and isinstance(y, int) and isinstance(z, int):\n # Check if any number is equal to the sum of the other two\n return x == y + z or y == x + z or z == x + y\n \n return False\n "} +{"task_id": "HumanEval/93", "completion": "vowels = 'aeiouAEIOU'\n encoded_message = []\n \n for char in message:\n if char.isalpha():\n # Swap case\n if char in vowels:\n # Replace vowel with the letter that appears 2 places ahead\n if char.lower() == 'a':\n new_char = 'c' if char.islower() else 'C'\n elif char.lower() == 'e':\n new_char = 'g' if char.islower() else 'G'\n elif char.lower() == 'i':\n new_char = 'k' if char.islower() else 'K'\n elif char.lower() == 'o':\n new_char = 'q' if char.islower() else 'Q'\n elif char.lower() == 'u':\n new_char = 'w' if char.islower() else 'W'\n else:\n new_char = char.swapcase()\n encoded_message.append(new_char)\n else:\n # Non-alphabetic characters remain unchanged\n encoded_message.append(char)\n\n return ''.join(encoded_message)\n "} +{"task_id": "HumanEval/94", "completion": " \"\"\"Check if a number is prime.\"\"\"\n if num <= 1:\n return False\n for i in range(2, int(num**0.5) + 1):\n if num % i == 0:\n return False\n return True\n\n \"\"\"Return the sum of the digits of a number.\"\"\"\n return sum(int(digit) for digit in str(n))\n\nlargest_prime = -1 # Start with an invalid prime number\nfor number in lst:\n if is_prime(number) and number > largest_prime:\n largest_prime = number\n\nif largest_prime == -1: # If no prime number was found\n return 0\n\nreturn sum_of_digits(largest_prime)\n "} +{"task_id": "HumanEval/95", "completion": "if not input_dict:\n return False\n\n all_lower = all(isinstance(key, str) and key.islower() for key in input_dict.keys())\n all_upper = all(isinstance(key, str) and key.isupper() for key in input_dict.keys())\n\n return all_lower or all_upper\n "} +{"task_id": "HumanEval/96", "completion": " if num < 2:\n return False\n for i in range(2, int(num**0.5) + 1):\n if num % i == 0:\n return False\n return True\n\n primes = []\n for i in range(n):\n if is_prime(i):\n primes.append(i)\n return primes\n "} +{"task_id": "HumanEval/97", "completion": "unit_digit_a = abs(a) % 10 # Get unit digit of a\n unit_digit_b = abs(b) % 10 # Get unit digit of b\n product = unit_digit_a * unit_digit_b # Calculate the product\n return product # Return the result\n "} +{"task_id": "HumanEval/98", "completion": "count = 0\n for i in range(0, len(s), 2): # Iterate over even indices\n if s[i] in 'AEIOU': # Check if the character is an uppercase vowel\n count += 1\n return count\n "} +{"task_id": "HumanEval/99", "completion": "import math\n\n # Convert the input string to a float\n number = float(value)\n \n # Get the floor and ceiling of the number\n lower_int = math.floor(number)\n upper_int = math.ceil(number)\n\n # Determine the difference from the number\n diff_lower = abs(number - lower_int)\n diff_upper = abs(number - upper_int)\n\n # If the number is equidistant, we round away from zero\n if diff_lower < diff_upper:\n return lower_int\n elif diff_upper < diff_lower:\n return upper_int\n else: # diff_lower == diff_upper\n # Choose the one that is farther from zero\n if lower_int < 0 and upper_int > 0:\n return upper_int # upper is the farther one\n elif lower_int > 0 and upper_int < 0:\n return lower_int # lower is the farther one\n elif lower_int < 0:\n return upper_int # both are negative, upper is farther\n else:\n return lower_int # both are positive, lower is farther\n "} +{"task_id": "HumanEval/100", "completion": " stones = []\n current_stones = n\n\n for i in range(n):\n stones.append(current_stones)\n current_stones += 2 # Increments by 2 consistently for both odd or even numbers\n \n return stones\n "} +{"task_id": "HumanEval/101", "completion": " return s.replace(',', ' ').split()\n "} +{"task_id": "HumanEval/102", "completion": "start = min(x, y)\n end = max(x, y)\n \n for num in range(end, start - 1, -1):\n if num % 2 == 0:\n return num\n \n return -1\n "} +{"task_id": "HumanEval/103", "completion": "if n > m:\n return -1 # Return -1 if n is greater than m\n \n # Calculate the sum and the count of numbers in the range n to m\n total_count = m - n + 1\n total_sum = sum(range(n, m + 1))\n \n # Calculate the average\n average = total_sum / total_count\n \n # Round to the nearest integer\n rounded_average = round(average)\n \n # Convert to binary\n binary_result = bin(rounded_average)\n \n return binary_result\n "} +{"task_id": "HumanEval/104", "completion": " return any(int(digit) % 2 == 0 for digit in str(num))\n \n result = [num for num in x if not has_even_digits(num)]\n return sorted(result)\n "} +{"task_id": "HumanEval/105", "completion": "filtered = [x for x in arr if 1 <= x <= 9]\n if not filtered:\n return []\n sorted_arr = sorted(filtered)\n reversed_arr = sorted_arr[::-1]\n num_to_word = [\"Zero\", \"One\", \"Two\", \"Three\", \"Four\", \"Five\", \"Six\", \"Seven\", \"Eight\", \"Nine\"]\n return [num_to_word[num] for num in reversed_arr]\n "} +{"task_id": "HumanEval/106", "completion": " \"\"\" Returns a list where the value of the element at index i (1-indexed)\n is the factorial of i if i is even, or the sum of numbers from 1 to i if i is odd.\n \"\"\"\n \n if not isinstance(n, int) or n < 1:\n raise ValueError(\"Input must be a positive integer.\")\n \n result = []\n factorial_cache = [1] # Start with 0! = 1 (not used but simplifies index calculation)\n\n for i in range(1, n + 1):\n if i % 2 == 0: # i is even\n # Calculate factorial using cached values\n factorial = factorial_cache[-1] * i # use the last cached factorial\n factorial_cache.append(factorial) # store the new factorial\n result.append(factorial)\n else: # i is odd\n # Calculate sum of numbers from 1 to i\n sum_of_numbers = sum(range(1, i + 1))\n result.append(sum_of_numbers)\n \n return result\n "} +{"task_id": "HumanEval/107", "completion": "even_count = 0\n odd_count = 0\n\n for i in range(1, n + 1):\n if str(i) == str(i)[::-1]: # Check if the number is a palindrome\n if i % 2 == 0:\n even_count += 1 # Increment even count\n else:\n odd_count += 1 # Increment odd count\n\n return (even_count, odd_count)\n "} +{"task_id": "HumanEval/108", "completion": " n_str = str(n)\n signed_sum = int(n_str[0]) # Start with the first digit (signed)\n \n for digit in n_str[1:]:\n signed_sum += int(digit) # Add the rest of the digits as normal\n\n return signed_sum\n\n count = 0\n for number in arr:\n if sum_of_digits(number) > 0:\n count += 1\n return count\n "} +{"task_id": "HumanEval/109", "completion": "if not arr:\n return True\n \n breaks = 0\n n = len(arr)\n \n for i in range(n):\n if arr[i] > arr[(i + 1) % n]:\n breaks += 1\n \n return breaks <= 1\n "} +{"task_id": "HumanEval/110", "completion": "# Check if lst1 is already all even\nif all(x % 2 == 0 for x in lst1):\n return \"YES\"\n\n# Count odd numbers in lst1\nodds_in_lst1 = sum(1 for x in lst1 if x % 2 != 0)\n# Count even numbers in lst2\nevens_in_lst2 = sum(1 for x in lst2 if x % 2 == 0)\n\n# Check if we have enough evens in lst2 to replace odds in lst1\nif odds_in_lst1 <= evens_in_lst2:\n return \"YES\"\nelse:\n return \"NO\"\n "} +{"task_id": "HumanEval/111", "completion": "\n letters = test.split()\n count_dict = {}\n for letter in letters:\n count_dict[letter] = count_dict.get(letter, 0) + 1\n max_count = max(count_dict.values(), default=0)\n return {letter: count for letter, count in count_dict.items() if count == max_count}\n "} +{"task_id": "HumanEval/112", "completion": "filtered_string = ''.join(char for char in s if char not in c)\n is_palindrome = filtered_string == filtered_string[::-1]\n return (filtered_string, is_palindrome)\n "} +{"task_id": "HumanEval/113", "completion": "result = []\nfor string in lst:\n # Count odd digits\n odd_count = sum(1 for char in string if char in '13579')\n # Create the output string\n output_string = f\"the number of odd elements {odd_count}n the str{odd_count}ng {odd_count} of the {odd_count}nput.\"\n result.append(output_string)\n\nreturn result\n "} +{"task_id": "HumanEval/114", "completion": "# Initialize current minimum and global minimum\n current_min = nums[0]\n global_min = nums[0]\n\n # Iterate through the array starting from the first element\n for i in range(1, len(nums)):\n current_min = min(current_min + nums[i], nums[i]) # Update current minimum subarray sum\n global_min = min(global_min, current_min) # Update global minimum sum if necessary\n\n return global_min\n "} +{"task_id": "HumanEval/115", "completion": "total_dips = 0\n \n for row in grid:\n # Count the total amount of water in the current row\n water_amount = sum(row)\n \n # Calculate the number of times we need to dip the buckets for this row\n total_dips += (water_amount + capacity - 1) // capacity\n \n return total_dips\n "} +{"task_id": "HumanEval/116", "completion": "return sorted(arr, key=lambda x: (bin(x).count('1'), x))\n "} +{"task_id": "HumanEval/117", "completion": " \"\"\"Helper function to check if a character is a consonant.\"\"\"\n return c.isalpha() and c.lower() not in 'aeiou'\n\n \"\"\"Helper function to count the number of consonants in a word.\"\"\"\n return sum(1 for char in word if is_consonant(char))\n "} +{"task_id": "HumanEval/118", "completion": "vowels = \"aeiouAEIOU\"\n last_consonant = None\n \n for i in range(len(word) - 1, 0, -1):\n if word[i] in vowels:\n if last_consonant:\n return word[i]\n elif word[i].isalpha() and word[i] not in vowels:\n last_consonant = word[i]\n \n return \"\"\n "} +{"task_id": "HumanEval/119", "completion": " balance = 0\n for char in s:\n if char == '(':\n balance += 1\n else: # char == ')'\n balance -= 1\n if balance < 0:\n return False\n return balance == 0\n\ns1, s2 = lst[0], lst[1]\nif is_balanced(s1 + s2) or is_balanced(s2 + s1):\n return 'Yes'\nreturn 'No'\n "} +{"task_id": "HumanEval/120", "completion": "if k == 0: # If k is 0, return an empty list\n return []\n\n largest_k = sorted(arr, reverse=True)[:k] # Get the k largest elements\n return sorted(largest_k) # Sort them in ascending order\n "} +{"task_id": "HumanEval/121", "completion": "return sum(lst[i] for i in range(0, len(lst), 2) if lst[i] % 2 != 0)\n "} +{"task_id": "HumanEval/122", "completion": "return sum(x for x in arr[:k] if -10 < x < 100)\n "} +{"task_id": "HumanEval/123", "completion": "\n odd_numbers.append(1) # Ensure 1 is included\n "} +{"task_id": "HumanEval/124", "completion": "# Check if the date string is not empty.\n if not date:\n return False\n\n # Split the date string into parts and check the length\n parts = date.split('-')\n if len(parts) != 3:\n return False\n\n month, day, year = parts\n\n # Check if month, day, and year are all numeric\n if not (month.isdigit() and day.isdigit() and year.isdigit()):\n return False\n \n month = int(month)\n day = int(day)\n year = int(year)\n\n # Validate month\n if month < 1 or month > 12:\n return False\n\n # Validate day\n if day < 1:\n return False\n\n # Days validation based on the month\n if month in [1, 3, 5, 7, 8, 10, 12]:\n return day <= 31\n elif month in [4, 6, 9, 11]:\n return day <= 30\n elif month == 2:\n # Check for leap year for February\n is_leap = (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)\n return day <= 29 if is_leap else day <= 28\n\n return False\n "} +{"task_id": "HumanEval/125", "completion": "Great! Your implementation looks solid and follows the instructions perfectly. Here\u2019s the final output containing only the added piece of code:\n\n\n if ' ' in txt:\n return txt.split()\n elif ',' in txt:\n return txt.split(',')\n else:\n return sum(1 for char in txt if char.islower() and (ord(char) - ord('a')) % 2 == 1)\n "} +{"task_id": "HumanEval/126", "completion": "if not lst: # Check for an empty list\n return True\n\n seen = set() # To track unique elements\n\n for i in range(len(lst)):\n # Check for duplicates\n if lst[i] in seen:\n return False\n seen.add(lst[i])\n\n # Check if the list is sorted\n if i > 0 and lst[i] < lst[i - 1]: \n return False\n \n return True\n "} +{"task_id": "HumanEval/127", "completion": " \"\"\"Check if a number is prime.\"\"\"\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n\n \"\"\"Determine if the length of intersection of two intervals is a prime number.\"\"\"\n start = max(interval1[0], interval2[0])\n end = min(interval1[1], interval2[1])\n \n if start >= end:\n return \"NO\"\n \n length = end - start\n\n if is_prime(length):\n return \"YES\"\n else:\n return \"NO\"\n "} +{"task_id": "HumanEval/128", "completion": " "} +{"task_id": "HumanEval/129", "completion": "\n best_path = [[]] # Initialize with an empty path\n "} +{"task_id": "HumanEval/130", "completion": "# We need to return the correct number of tribonacci values as described.\n \"\"\"Return a list of the first n + 1 numbers of the Tribonacci sequence.\"\"\"\n \n # List to store tribonacci numbers\n sequence = []\n \n # Function to calculate tribonacci values with memoization\n def calculate_tri(x, memo):\n if x in memo:\n return memo[x]\n\n if x == 1:\n value = 3\n elif x % 2 == 0: # even\n value = 1 + x / 2\n else: # odd\n # Corrected this part to calculate correctly\n value = calculate_tri(x - 1, memo) + calculate_tri(x - 2, memo) + calculate_tri(x + 1, memo)\n \n memo[x] = value\n return value\n \n # Memoization dictionary\n memo = {}\n \n for i in range(n + 1):\n sequence.append(calculate_tri(i + 1, memo)) # Adjusting the index to start from 1 for tri\n\n return sequence\n\n# Example usage\nprint(tri(3)) # It should output [3, 2, 8, 3] as discussed\n "} +{"task_id": "HumanEval/131", "completion": "product = 1\n has_odd_digit = False # Flag to check if there's at least one odd digit\n\n for digit in str(n): # Convert n to string to iterate through each digit\n d = int(digit) # Convert digit back to integer\n if d % 2 == 1: # Check if the digit is odd\n product *= d\n has_odd_digit = True # We found at least one odd digit\n\n return product if has_odd_digit else 0 # Return product or 0\n "} +{"task_id": "HumanEval/132", "completion": "stack = []\n # A flag to check for nesting\n has_nested = False\n \n for char in string:\n if char == '[':\n stack.append(char)\n # If the last element was also an opening bracket,\n # this means we have found a nested opening bracket.\n if len(stack) > 1:\n has_nested = True\n elif char == ']':\n if stack: # There must be a corresponding opening bracket\n stack.pop()\n else:\n return False # Unmatched closing bracket\n \n # Check if the brackets are balanced and if there's any nesting\n return has_nested and not stack\n "} +{"task_id": "HumanEval/133", "completion": "import math\n\n return sum(math.ceil(x) ** 2 for x in lst)\n "} +{"task_id": "HumanEval/134", "completion": "txt = txt.rstrip() # Remove trailing whitespace\n if len(txt) == 0: # Check for empty string\n return False\n last_char = txt[-1] # Get the last character\n if last_char.isalpha() and (len(txt) == 1 or not txt[-2].isalpha()):\n return True\n return False\n "} +{"task_id": "HumanEval/135", "completion": "largest_index = -1 # Start with -1 indicating no such index found\n\n # Iterate through the array starting from the second element\n for i in range(1, len(arr)):\n if arr[i] < arr[i - 1]: # Check if current element is less than the previous\n largest_index = i # Update largest_index with the current index\n \n return largest_index\n "} +{"task_id": "HumanEval/136", "completion": "max_neg = None\n min_pos = None\n \n for num in lst:\n if num < 0:\n if max_neg is None or num > max_neg:\n max_neg = num\n elif num > 0:\n if min_pos is None or num < min_pos:\n min_pos = num\n \n return (max_neg, min_pos)\n "} +{"task_id": "HumanEval/137", "completion": " def convert_to_float(value):\n try:\n if isinstance(value, str):\n value = value.replace(',', '.') # Handle European-style decimal\n return float(value)\n except ValueError:\n return None # Return None if conversion fails\n\n float_a = convert_to_float(a)\n float_b = convert_to_float(b)\n\n if float_a is None or float_b is None:\n return None # If either value cannot be converted\n\n if float_a > float_b:\n return a # Return the original type of 'a'\n elif float_a < float_b:\n return b # Return the original type of 'b'\n else:\n return None # Values are equal\n "} +{"task_id": "HumanEval/138", "completion": "if n < 8:\n return False\n return n % 2 == 0\n "} +{"task_id": "HumanEval/139", "completion": "import math\n\n \"\"\"The Brazilian factorial is defined as:\n brazilian_factorial(n) = n! * (n-1)! * (n-2)! * ... * 1!\n where n > 0\n\n For example:\n >>> special_factorial(4)\n 288\n \"\"\"\n if n <= 0:\n raise ValueError(\"Input must be a positive integer\")\n\n result = 1\n for i in range(1, n + 1):\n result *= math.factorial(i)\n\n return result\n "} +{"task_id": "HumanEval/140", "completion": "import re\n\n text = re.sub(r' {3,}', '-', text) # Replace sequences of 3 or more spaces with a hyphen\n text = re.sub(r'^\\s+', '_', text) # Replace a single leading space with an underscore\n text = re.sub(r' ', '_', text) # Replace all single spaces with underscores\n \n return text\n "} +{"task_id": "HumanEval/141", "completion": " # Step 1: Check for exactly one dot in the file name\n if file_name.count('.') != 1:\n return 'No'\n \n # Split the file name into the name part and the extension part\n name, extension = file_name.split('.')\n \n # Step 2: Check that the name part is not empty and starts with a letter\n if not name or not name[0].isalpha():\n return 'No'\n \n # Step 3: Check that the extension is one of the valid options\n if extension not in ['txt', 'exe', 'dll']:\n return 'No'\n \n # Step 4: Count the number of digits in the file name\n digit_count = sum(c.isdigit() for c in file_name)\n if digit_count > 3:\n return 'No'\n \n # If all conditions are met, the file name is valid\n return 'Yes'\n "} +{"task_id": "HumanEval/142", "completion": "total_sum = 0\n \n for index, value in enumerate(lst):\n if index % 3 == 0:\n total_sum += value ** 2\n elif index % 4 == 0:\n total_sum += value ** 3\n else:\n total_sum += value\n \n return total_sum\n "} +{"task_id": "HumanEval/143", "completion": " \"\"\"Check if a number is prime.\"\"\"\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n\nwords = sentence.split()\nfiltered_words = [word for word in words if is_prime(len(word))]\nreturn ' '.join(filtered_words)\n "} +{"task_id": "HumanEval/144", "completion": "# Split the fractions into numerator and denominator\n x_numerator, x_denominator = map(int, x.split('/'))\n n_numerator, n_denominator = map(int, n.split('/'))\n\n # Calculate the new numerator and denominator\n new_numerator = x_numerator * n_numerator\n new_denominator = x_denominator * n_denominator\n\n # Check if the result is a whole number\n return new_numerator % new_denominator == 0\n "} +{"task_id": "HumanEval/145", "completion": " def sum_of_digits(n):\n return sum(int(digit) for digit in str(abs(n)))\n\n return sorted(nums, key=lambda x: (sum_of_digits(x), nums.index(x)))\n "} +{"task_id": "HumanEval/146", "completion": "count = 0\nfor num in nums:\n if num > 10:\n num_str = str(num)\n first_digit = int(num_str[0])\n last_digit = int(num_str[-1])\n if first_digit % 2 != 0 and last_digit % 2 != 0:\n count += 1\nreturn count\n "} +{"task_id": "HumanEval/147", "completion": " a = [i * i - i + 1 for i in range(1, n + 1)]\n count = 0\n \n for i in range(n):\n for j in range(i + 1, n):\n for k in range(j + 1, n):\n if (a[i] + a[j] + a[k]) % 3 == 0:\n count += 1\n \n return count\n "} +{"task_id": "HumanEval/148", "completion": "planets = [\"Mercury\", \"Venus\", \"Earth\", \"Mars\", \"Jupiter\", \"Saturn\", \"Uranus\", \"Neptune\"]\n \n if planet1 not in planets or planet2 not in planets:\n return ()\n \n idx1 = planets.index(planet1)\n idx2 = planets.index(planet2)\n \n if idx1 > idx2:\n idx1, idx2 = idx2, idx1\n \n return tuple(planets[idx1 + 1: idx2])\n "} +{"task_id": "HumanEval/149", "completion": "# Additional test cases\nassert sorted_list_sum([\"hello\", \"world\", \"hi\", \"python\"]) == [\"hello\", \"world\", \"python\"]\nassert sorted_list_sum([\"cat\", \"dog\", \"elephant\", \"bird\"]) == [\"dog\", \"cat\"]\nassert sorted_list_sum([\"apple\", \"banana\", \"kiwi\", \"pear\", \"grape\"]) == [\"kiwi\", \"pear\"]\nassert sorted_list_sum([\"aaa\", \"bb\", \"c\", \"dddd\"]) == [\"bb\", \"dddd\"]\nassert sorted_list_sum([\"\"]) == [\"\"] # Testing with an empty string\nassert sorted_list_sum([]) == [] # Testing with an empty list\nassert sorted_list_sum([\"a\", \"ab\", \"abc\", \"abcd\", \"abcde\"]) == [\"ab\", \"abcd\"] # Odd lengths removed\n\nprint(\"All tests passed successfully!\")\n "} +{"task_id": "HumanEval/150", "completion": " \"\"\"Helper function to check if a number is prime.\"\"\"\n if num <= 1:\n return False\n for i in range(2, int(num**0.5) + 1):\n if num % i == 0:\n return False\n return True\n\nif is_prime(n):\n return x\nelse:\n return y\n "} +{"task_id": "HumanEval/151", "completion": "\n return sum(x**2 for x in lst if isinstance(x, int) and x >= 0 and x % 2 != 0)\n "} +{"task_id": "HumanEval/152", "completion": "return [abs(g - m) for m, g in zip(game, guess)]\n "} +{"task_id": "HumanEval/153", "completion": "strongest_extension = None\nmax_strength = float('-inf') # Start with the lowest possible value\n\nfor extension in extensions:\n CAP = sum(1 for char in extension if char.isupper())\n SM = sum(1 for char in extension if char.islower())\n strength = CAP - SM\n\n # Check if we have found a stronger extension or if it's the first one\n if strength > max_strength:\n max_strength = strength\n strongest_extension = extension\n\nreturn f\"{class_name}.{strongest_extension}\"\n "} +{"task_id": "HumanEval/154", "completion": "if len(b) == 0:\n return True # An empty string is always a substring\n b_rotated = b + b\n return any(a.find(b_rotated[i:i+len(b)]) != -1 for i in range(len(b)))\n "} +{"task_id": "HumanEval/155", "completion": "num_str = str(abs(num))\n \n even_count = 0\n odd_count = 0\n \n for digit in num_str:\n if int(digit) % 2 == 0:\n even_count += 1\n else:\n odd_count += 1\n \n return (even_count, odd_count)\n "} +{"task_id": "HumanEval/156", "completion": "roman_numerals = [\n (1000, 'm'), (900, 'cm'), (500, 'd'), (400, 'cd'),\n (100, 'c'), (90, 'xc'), (50, 'l'), (40, 'xl'),\n (10, 'x'), (9, 'ix'), (5, 'v'), (4, 'iv'), (1, 'i')\n ]\n \n result = []\n \n for value, roman in roman_numerals:\n while number >= value:\n result.append(roman)\n number -= value\n \n return ''.join(result)\n "} +{"task_id": "HumanEval/157", "completion": "sides = sorted([a, b, c])\n return sides[0]**2 + sides[1]**2 == sides[2]**2\n "} +{"task_id": "HumanEval/158", "completion": "\n max_unique_count = 0\n result_word = \"\"\n \n for word in words:\n unique_chars = set(word)\n unique_count = len(unique_chars)\n \n if unique_count > max_unique_count:\n max_unique_count = unique_count\n result_word = word\n elif unique_count == max_unique_count:\n if word < result_word:\n result_word = word\n \n return result_word\n "} +{"task_id": "HumanEval/159", "completion": "additional_needed = need - number\n \n if remaining >= additional_needed:\n eaten = additional_needed\n else:\n eaten = remaining\n \n total_eaten = number + eaten\n remaining_after_meals = remaining - eaten\n \n return [total_eaten, remaining_after_meals]\n "} +{"task_id": "HumanEval/160", "completion": "\n result = operands[0]\n for i in range(len(operators)):\n if operators[i] == '+':\n result += operands[i + 1]\n elif operators[i] == '-':\n result -= operands[i + 1]\n elif operators[i] == '*':\n result *= operands[i + 1]\n elif operators[i] == '//':\n result //= operands[i + 1]\n elif operators[i] == '**':\n result **= operands[i + 1]\n return result\n "} +{"task_id": "HumanEval/161", "completion": "has_letter = any(c.isalpha() for c in s)\n \n if has_letter:\n result = ''.join(c.lower() if c.isupper() else c.upper() for c in s)\n else:\n result = s[::-1]\n \n return result\n "} +{"task_id": "HumanEval/162", "completion": "import hashlib\n\n \"\"\"\n Given a string 'text', return its md5 hash equivalent string.\n If 'text' is an empty string, return None.\n\n >>> string_to_md5('Hello world') == '3e25960a79dbc69b674cd4ec67a72c62'\n \"\"\"\n if not text:\n return None\n \n return hashlib.md5(text.encode()).hexdigest()\n "} +{"task_id": "HumanEval/163", "completion": " \"\"\"\n Given two positive integers a and b, return the even digits between a\n and b, in ascending order.\n \"\"\"\n # Determine the range\n start = min(a, b)\n end = max(a, b)\n \n # Generate a list of even integers in the specified range\n even_integers = [num for num in range(start, end + 1) if num % 2 == 0]\n \n return even_integers\n\n# Example usage\nprint(generate_integers(2, 8)) # Output: [2, 4, 6, 8]\nprint(generate_integers(8, 2)) # Output: [2, 4, 6, 8]\nprint(generate_integers(10, 14)) # Output: []\n "} diff --git a/experiment/humaneval/bash_with_aios.sh b/experiment/humaneval/bash_with_aios.sh new file mode 100644 index 000000000..697082f1b --- /dev/null +++ b/experiment/humaneval/bash_with_aios.sh @@ -0,0 +1,8 @@ +python -m experiment.humaneval.inference \ + --data_name openai/openai_humaneval \ + --split test \ + --output_file experiment/humaneval/autogen_prediction.json \ + --on_aios \ + --agent_type autogen \ + --llm_name gpt-4o-mini \ + --max_new_tokens 8000 \ No newline at end of file diff --git a/experiment/humaneval/convert.py b/experiment/humaneval/convert.py new file mode 100644 index 000000000..24b1b3578 --- /dev/null +++ b/experiment/humaneval/convert.py @@ -0,0 +1,12 @@ +import json + +# Load the JSON data +with open('interpreter_prediction.json', 'r') as json_file: + data = json.load(json_file) + +# Write to JSONL file +with open('interpreter_prediction.jsonl', 'w') as jsonl_file: + for entry in data: + entry["completion"] = entry["result"] + entry.pop("result") + jsonl_file.write(json.dumps(entry) + '\n') diff --git a/experiment/humaneval/inference.py b/experiment/humaneval/inference.py new file mode 100644 index 000000000..c4b63157b --- /dev/null +++ b/experiment/humaneval/inference.py @@ -0,0 +1,82 @@ +import json +import re +from typing import List +from datasets import load_dataset +from aios.hooks.starter import aios_starter +from experiment.agent.experiment_agent import ExpirementAgent +from experiment.experiment_core import logger, MetaData, AGENT_TYPE_MAPPING_AIOS, run_inference +from experiment.utils import get_args + + +def parse_result(result: str): + match = re.search(r'```python\s*([\s\S]*?)```', result) + if match: + result = match.group(1) + + if not result.startswith("def") or not result.startswith("import"): + result += " " + + code_lines = result.split("\n") + for line in code_lines[:]: + if line.startswith("def"): + code_lines.remove(line) + elif line.startswith("import"): + line += " " + result = "\n".join(code_lines) + + return result + + +def write_output_func(result_list: List, output_file: str): + with open(output_file, "w", encoding="utf-8") as file: + for result in result_list: + json_line = json.dumps(result) + file.write(json_line + "\n") + logger.log(f"Write results num: {len(result_list)}", level="info") + + +def process_one_func(data, meta_data: MetaData): + if meta_data.on_aios: + with aios_starter(**meta_data.aios_args): + agent: ExpirementAgent = AGENT_TYPE_MAPPING_AIOS[meta_data.agent_type](meta_data.on_aios) + result = agent.run(data["prompt"]) + result = parse_result(result) + + prediction = { + "task_id": data["task_id"], + "completion": result, + } + return prediction + + else: + agent: ExpirementAgent = AGENT_TYPE_MAPPING_AIOS[meta_data.agent_type](meta_data.on_aios) + result = agent.run(data["prompt"]) + result = parse_result(result) + + prediction = { + "task_id": data["task_id"], + "completion": result, + } + return prediction + + +if __name__ == '__main__': + main_args, global_args = get_args() + + agent_type = "humaneval:" + main_args.agent_type + dataset = load_dataset(main_args.data_name, split=main_args.split) + + meta = MetaData( + dataset=dataset, + agent_type=agent_type, + output_file=main_args.output_file, + on_aios=main_args.on_aios, + max_num=main_args.max_num, + aios_args=vars(global_args), + ) + + run_inference( + meta_data=meta, + process_one_func=process_one_func, + write_output_func=write_output_func, + ) diff --git a/experiment/humaneval/interpreter_prediction.json b/experiment/humaneval/interpreter_prediction.json new file mode 100644 index 000000000..ae382b25a --- /dev/null +++ b/experiment/humaneval/interpreter_prediction.json @@ -0,0 +1,658 @@ +[ + { + "task_id": "HumanEval/0", + "result": "for i in range(len(numbers)):\n for j in range(i + 1, len(numbers)):\n if abs(numbers[i] - numbers[j]) < threshold:\n return True\n return False\n" + }, + { + "task_id": "HumanEval/1", + "result": "def separate_paren_groups(paren_string: str) -> List[str]:\n paren_string = paren_string.replace(\" \", \"\") # Step 1: Remove spaces\n result = []\n stack = []\n current_group = []\n\n for char in paren_string:\n if char == '(':\n if not stack: # Starting a new group\n current_group = [] # Reset current group\n stack.append(char)\n current_group.append(char) # Add to current group\n elif char == ')':\n stack.pop()\n current_group.append(char) # Add to current group\n if not stack: # If stack is empty, a complete group is found\n result.append(''.join(current_group)) # Add to result\n\n return result\n" + }, + { + "task_id": "HumanEval/2", + "result": "def truncate_number(number: float) -> float:\n return number - int(number)\n" + }, + { + "task_id": "HumanEval/3", + "result": "def below_zero(operations: List[int]) -> bool:\n balance = 0\n for operation in operations:\n balance += operation\n if balance < 0:\n return True\n return False\n" + }, + { + "task_id": "HumanEval/4", + "result": "mean_value = sum(numbers) / len(numbers) # Calculate mean\ndeviations = [abs(x - mean_value) for x in numbers] # Calculate absolute differences\nreturn sum(deviations) / len(deviations) # Calculate and return MAD\n" + }, + { + "task_id": "HumanEval/5", + "result": "def intersperse(numbers: List[int], delimeter: int) -> List[int]:\n if not numbers:\n return []\n \n result = []\n for i in range(len(numbers)):\n result.append(numbers[i])\n if i < len(numbers) - 1: # Don't add delimeter after the last element\n result.append(delimeter)\n \n return result\n" + }, + { + "task_id": "HumanEval/6", + "result": "def parse_nested_parens(paren_string: str) -> List[int]:\n depths = []\n groups = paren_string.split()\n\n for group in groups:\n max_depth = 0\n current_depth = 0\n \n for char in group:\n if char == '(':\n current_depth += 1\n max_depth = max(max_depth, current_depth)\n elif char == ')':\n current_depth -= 1\n \n depths.append(max_depth)\n\n return depths\n" + }, + { + "task_id": "HumanEval/7", + "result": "return [s for s in strings if substring in s]\n" + }, + { + "task_id": "HumanEval/8", + "result": "def sum_product(numbers: List[int]) -> Tuple[int, int]:\n total_sum = sum(numbers)\n total_product = 1\n for number in numbers:\n total_product *= number\n return total_sum, total_product\n" + }, + { + "task_id": "HumanEval/9", + "result": "def rolling_max(numbers: List[int]) -> List[int]:\n max_so_far = float('-inf')\n rolling_max_list = []\n\n for number in numbers:\n if number > max_so_far:\n max_so_far = number\n rolling_max_list.append(max_so_far)\n\n return rolling_max_list\n" + }, + { + "task_id": "HumanEval/10", + "result": "def make_palindrome(string: str) -> str:\n def is_palindrome(s: str) -> bool:\n return s == s[::-1]\n\n for i in range(len(string)):\n if is_palindrome(string[i:]):\n return string + string[:i][::-1]\n \n return string\n" + }, + { + "task_id": "HumanEval/11", + "result": "result = ''.join(str(int(x) ^ int(y)) for x, y in zip(a, b))\n" + }, + { + "task_id": "HumanEval/12", + "result": "def longest(strings: List[str]) -> Optional[str]:\n if not strings:\n return None\n longest_string = \"\"\n for string in strings:\n if len(string) > len(longest_string):\n longest_string = string\n return longest_string\n" + }, + { + "task_id": "HumanEval/13", + "result": "def greatest_common_divisor(a: int, b: int) -> int:\n while b:\n a, b = b, a % b\n return a\n" + }, + { + "task_id": "HumanEval/14", + "result": "return [string[:i] for i in range(1, len(string) + 1)]\n" + }, + { + "task_id": "HumanEval/15", + "result": "return ' '.join(str(i) for i in range(n + 1))\n" + }, + { + "task_id": "HumanEval/16", + "result": "return len(set(string.lower()))\n" + }, + { + "task_id": "HumanEval/17", + "result": "def parse_music(music_string: str) -> List[int]:\n note_duration_map = {\n 'o': 4,\n 'o|': 2,\n '.|': 1\n }\n \n notes = music_string.split()\n durations = [note_duration_map[note] for note in notes]\n \n return durations\n" + }, + { + "task_id": "HumanEval/18", + "result": "def how_many_times(string: str, substring: str) -> int:\n count = 0\n start = 0\n\n while True:\n start = string.find(substring, start)\n if start == -1:\n break\n count += 1\n start += 1 # Move to the next character to allow for overlapping\n\n return count\n" + }, + { + "task_id": "HumanEval/19", + "result": "def sort_numbers(numbers: str) -> str:\n number_map = {\n 'zero': 0,\n 'one': 1,\n 'two': 2,\n 'three': 3,\n 'four': 4,\n 'five': 5,\n 'six': 6,\n 'seven': 7,\n 'eight': 8,\n 'nine': 9\n }\n \n words = numbers.split()\n sorted_numbers = sorted(words, key=lambda x: number_map[x])\n return ' '.join(sorted_numbers)\n" + }, + { + "task_id": "HumanEval/20", + "result": "def find_closest_elements(numbers: List[float]) -> Tuple[float, float]:\n numbers.sort()\n closest_pair = (numbers[0], numbers[1])\n min_diff = abs(numbers[1] - numbers[0])\n \n for i in range(1, len(numbers) - 1):\n diff = abs(numbers[i + 1] - numbers[i])\n if diff < min_diff:\n min_diff = diff\n closest_pair = (numbers[i], numbers[i + 1])\n \n return closest_pair\n" + }, + { + "task_id": "HumanEval/21", + "result": "return [(num - min_val) / (max_val - min_val) for num in numbers]\n" + }, + { + "task_id": "HumanEval/22", + "result": "return [value for value in values if isinstance(value, int)]\n" + }, + { + "task_id": "HumanEval/23", + "result": "return len(string)\n" + }, + { + "task_id": "HumanEval/24", + "result": "for i in range(n - 1, 0, -1):\n if n % i == 0:\n return i\n" + }, + { + "task_id": "HumanEval/25", + "result": "def factorize(n: int) -> List[int]:\n factors = []\n while n % 2 == 0:\n factors.append(2)\n n //= 2\n for i in range(3, int(n**0.5) + 1, 2):\n while n % i == 0:\n factors.append(i)\n n //= i\n if n > 2:\n factors.append(n)\n return factors\n" + }, + { + "task_id": "HumanEval/26", + "result": "def remove_duplicates(numbers: List[int]) -> List[int]:\n counts = {}\n for number in numbers:\n counts[number] = counts.get(number, 0) + 1\n \n return [number for number in numbers if counts[number] == 1]\n" + }, + { + "task_id": "HumanEval/27", + "result": "return string.swapcase()\n" + }, + { + "task_id": "HumanEval/28", + "result": "def concatenate(strings: List[str]) -> str:\n return ''.join(strings)\n" + }, + { + "task_id": "HumanEval/29", + "result": "def filter_by_prefix(strings: List[str], prefix: str) -> List[str]:\n return [s for s in strings if s.startswith(prefix)]\n" + }, + { + "task_id": "HumanEval/30", + "result": "def get_positive(l: list):\n return [num for num in l if num > 0]\n" + }, + { + "task_id": "HumanEval/31", + "result": "def is_prime(n):\n if n < 2:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n" + }, + { + "task_id": "HumanEval/32", + "result": "def find_zero(xs: list):\n \"\"\" xs are coefficients of a polynomial. \n find_zero finds x such that poly(x) = 0.\n \"\"\"\n # Contains the polynomial function\n def poly_derivative(xs, x):\n \"\"\" Evaluates the derivative of polynomial with coefficients xs at point x. \"\"\"\n return sum([i * coeff * math.pow(x, i - 1) for i, coeff in enumerate(xs) if i > 0])\n\n # Starting guess can be 0\n x0 = 0.0\n tolerance = 1e-7\n max_iterations = 1000\n for _ in range(max_iterations):\n fx = poly(xs, x0)\n dfx = poly_derivative(xs, x0)\n \n if dfx == 0: # Prevent division by zero\n break\n \n x1 = x0 - fx / dfx\n if abs(x1 - x0) < tolerance: # Check for convergence\n return x1\n x0 = x1\n \n return x0 # Return the last approximation\n" + }, + { + "task_id": "HumanEval/33", + "result": "def sort_third(l: list):\n sorted_third = sorted(l[i] for i in range(len(l)) if i % 3 == 0)\n \n result = l[:]\n j = 0\n for i in range(len(l)):\n if i % 3 == 0:\n result[i] = sorted_third[j]\n j += 1\n\n return result\n" + }, + { + "task_id": "HumanEval/34", + "result": "return sorted(set(l))\n" + }, + { + "task_id": "HumanEval/35", + "result": "def max_element(l: list):\n return max(l)\n" + }, + { + "task_id": "HumanEval/36", + "result": "count = 0\nfor i in range(n):\n if i % 11 == 0 or i % 13 == 0:\n count += str(i).count('7')\nreturn count\n" + }, + { + "task_id": "HumanEval/37", + "result": "def sort_even(l: list):\n even_indices = sorted(l[i] for i in range(0, len(l), 2))\n result = []\n even_index = 0\n for i in range(len(l)):\n if i % 2 == 0:\n result.append(even_indices[even_index])\n even_index += 1\n else:\n result.append(l[i])\n return result\n" + }, + { + "task_id": "HumanEval/38", + "result": "groups = [s[(3 * i):min((3 * i + 3), len(s))] for i in range((len(s) + 2) // 3)]\n groups = [(group[-1] + group[:-1]) if len(group) == 3 else group for group in groups]\n return \"\".join(groups)\n" + }, + { + "task_id": "HumanEval/39", + "result": "def is_prime(num):\n if num < 2:\n return False\n for i in range(2, int(num**0.5) + 1):\n if num % i == 0:\n return False\n return True\n\ndef prime_fib(n: int):\n fib1, fib2 = 0, 1\n prime_fib_count = 0\n current_prime_fib = None\n\n while prime_fib_count < n:\n fib1, fib2 = fib2, fib1 + fib2\n if is_prime(fib2):\n prime_fib_count += 1\n current_prime_fib = fib2\n\n return current_prime_fib\n" + }, + { + "task_id": "HumanEval/40", + "result": "def triples_sum_to_zero(l):\n n = len(l)\n for i in range(n):\n s = set()\n current_sum = -l[i]\n for j in range(i + 1, n):\n if (current_sum - l[j]) in s:\n return True\n s.add(l[j])\n return False\n" + }, + { + "task_id": "HumanEval/41", + "result": "def car_race_collision(n: int) -> int:\n return n * n\n" + }, + { + "task_id": "HumanEval/42", + "result": "def incr_list(l):\n return [x + 1 for x in l]\n" + }, + { + "task_id": "HumanEval/43", + "result": "def pairs_sum_to_zero(l):\n seen = set()\n for num in l:\n if -num in seen:\n return True\n seen.add(num)\n return False\n" + }, + { + "task_id": "HumanEval/44", + "result": "result = \"\"\n while x > 0:\n remainder = x % base\n result = str(remainder) + result # Prepend remainder to the result\n x //= base # Divide x by base\n return result if result else \"0\" # Handle case where x is 0\n" + }, + { + "task_id": "HumanEval/45", + "result": "def triangle_area(a, h):\n return 0.5 * a * h\n" + }, + { + "task_id": "HumanEval/46", + "result": "def fib4(n: int) -> int:\n if n == 0:\n return 0\n elif n == 1:\n return 0\n elif n == 2:\n return 2\n elif n == 3:\n return 0\n\n fib_sequence = [0, 0, 2, 0]\n for i in range(4, n + 1):\n next_value = fib_sequence[-1] + fib_sequence[-2] + fib_sequence[-3] + fib_sequence[-4]\n fib_sequence.append(next_value)\n\n return fib_sequence[n]\n" + }, + { + "task_id": "HumanEval/47", + "result": "l.sort()\n n = len(l)\n if n % 2 == 1: # odd length\n return l[n // 2]\n else: # even length\n return (l[n // 2 - 1] + l[n // 2]) / 2\n" + }, + { + "task_id": "HumanEval/48", + "result": "return text == text[::-1]\n" + }, + { + "task_id": "HumanEval/49", + "result": "return pow(2, n, p)\n" + }, + { + "task_id": "HumanEval/50", + "result": "def decode_shift(s: str):\n return \"\".join([chr(((ord(ch) - 5 - ord(\"a\")) % 26) + ord(\"a\")) for ch in s])\n" + }, + { + "task_id": "HumanEval/51", + "result": "def remove_vowels(text):\n vowels = \"aeiouAEIOU\"\n return ''.join([char for char in text if char not in vowels])\n" + }, + { + "task_id": "HumanEval/52", + "result": "for number in l:\n if number >= t:\n return False\nreturn True\n" + }, + { + "task_id": "HumanEval/53", + "result": "return x + y\n" + }, + { + "task_id": "HumanEval/54", + "result": "return set(s0) == set(s1)\n" + }, + { + "task_id": "HumanEval/55", + "result": "if n == 1 or n == 2:\n return 1\n a, b = 1, 1\n for _ in range(3, n + 1):\n a, b = b, a + b\n return b\n" + }, + { + "task_id": "HumanEval/56", + "result": "def correct_bracketing(brackets: str):\n count = 0\n for char in brackets:\n if char == \"<\":\n count += 1\n elif char == \">\":\n count -= 1\n if count < 0:\n return False\n return count == 0\n" + }, + { + "task_id": "HumanEval/57", + "result": "def monotonic(l: list):\n if len(l) <= 1:\n return True\n\n increasing = decreasing = True\n\n for i in range(1, len(l)):\n if l[i] > l[i - 1]:\n decreasing = False\n elif l[i] < l[i - 1]:\n increasing = False\n\n return increasing or decreasing\n" + }, + { + "task_id": "HumanEval/58", + "result": "def common(l1: list, l2: list):\n return sorted(set(l1) & set(l2))\n" + }, + { + "task_id": "HumanEval/59", + "result": "def largest_prime_factor(n):\n largest_factor = 1\n # Check for number of 2s that divide n\n while n % 2 == 0:\n largest_factor = 2\n n //= 2\n \n # n must be odd at this point, thus check for odd factors from 3\n for i in range(3, int(n**0.5) + 1, 2):\n while n % i == 0:\n largest_factor = i\n n //= i\n \n # This condition is to check if n is a prime number\n # greater than 2\n if n > 2:\n largest_factor = n\n \n return largest_factor\n" + }, + { + "task_id": "HumanEval/60", + "result": "def sum_to_n(n: int):\n return n * (n + 1) // 2\n" + }, + { + "task_id": "HumanEval/61", + "result": "def correct_bracketing(brackets: str) -> bool:\n counter = 0\n for char in brackets:\n if char == '(':\n counter += 1\n elif char == ')':\n counter -= 1\n if counter < 0:\n return False\n return counter == 0\n" + }, + { + "task_id": "HumanEval/62", + "result": "def derivative(xs):\n return [i * xs[i] for i in range(1, len(xs))]\n" + }, + { + "task_id": "HumanEval/63", + "result": "def fibfib(n: int, memo={0: 0, 1: 0, 2: 1}):\n if n in memo:\n return memo[n]\n memo[n] = fibfib(n-1, memo) + fibfib(n-2, memo) + fibfib(n-3, memo)\n return memo[n]\n" + }, + { + "task_id": "HumanEval/64", + "result": "def vowels_count(s):\n count = 0\n vowels = 'aeiou'\n \n for i, char in enumerate(s.lower()):\n if char in vowels or (char == 'y' and i == len(s) - 1):\n count += 1\n \n return count\n" + }, + { + "task_id": "HumanEval/65", + "result": "def circular_shift(x, shift):\n s = str(x)\n length = len(s)\n \n if shift > length:\n return s[::-1]\n \n shift = shift % length\n return s[-shift:] + s[:-shift]\n" + }, + { + "task_id": "HumanEval/66", + "result": "def digitSum(s):\n return sum(ord(char) for char in s if char.isupper())\n " + }, + { + "task_id": "HumanEval/67", + "result": "def fruit_distribution(s, n):\n apples = int(s.split()[0]) \n oranges = int(s.split()[3]) \n \n mangoes = n - apples - oranges\n return mangoes\n" + }, + { + "task_id": "HumanEval/68", + "result": "def pluck(arr):\n smallest_even = float('inf')\n smallest_index = -1\n \n for index, value in enumerate(arr):\n if value % 2 == 0: # Check if the value is even\n if value < smallest_even: # Check if it's the smallest even value\n smallest_even = value\n smallest_index = index\n\n if smallest_index == -1: # No even numbers found\n return []\n \n return [smallest_even, smallest_index]\n" + }, + { + "task_id": "HumanEval/69", + "result": "def search(lst):\n frequency = {}\n \n # Count frequency of each number\n for num in lst:\n if num in frequency:\n frequency[num] += 1\n else:\n frequency[num] = 1\n\n # Check for the greatest integer that meets the condition\n for num in sorted(frequency.keys(), reverse=True):\n if frequency[num] >= num:\n return num\n \n return -1\n" + }, + { + "task_id": "HumanEval/70", + "result": "def strange_sort_list(lst):\n lst.sort()\n result = []\n min_ptr, max_ptr = 0, len(lst) - 1\n \n while min_ptr <= max_ptr:\n if min_ptr == max_ptr:\n result.append(lst[min_ptr])\n else:\n result.append(lst[min_ptr])\n result.append(lst[max_ptr])\n \n min_ptr += 1\n max_ptr -= 1\n \n return result\n" + }, + { + "task_id": "HumanEval/71", + "result": "def triangle_area(a, b, c):\n if a + b > c and a + c > b and b + c > a: # Check validity\n s = (a + b + c) / 2 # Semi-perimeter\n area = (s * (s - a) * (s - b) * (s - c)) ** 0.5 # Heron's formula\n return round(area, 2) # Return area rounded to 2 decimal points\n return -1 # Not a valid triangle\n" + }, + { + "task_id": "HumanEval/72", + "result": "def will_it_fly(q, w):\n return q == q[::-1] and sum(q) <= w\n" + }, + { + "task_id": "HumanEval/73", + "result": "def smallest_change(arr):\n changes = 0\n n = len(arr)\n \n for i in range(n // 2):\n if arr[i] != arr[n - 1 - i]:\n changes += 1\n \n return changes\n" + }, + { + "task_id": "HumanEval/74", + "result": "def total_match(lst1, lst2):\n total_chars_lst1 = sum(len(s) for s in lst1)\n total_chars_lst2 = sum(len(s) for s in lst2)\n\n if total_chars_lst1 < total_chars_lst2:\n return lst1\n elif total_chars_lst1 > total_chars_lst2:\n return lst2\n else:\n return lst1\n" + }, + { + "task_id": "HumanEval/75", + "result": "def is_multiply_prime(a):\n primes = [prime(i) for i in range(1, 30) if prime(i) < 100]\n for combo in combinations(primes, 3):\n if combo[0] * combo[1] * combo[2] == a:\n return True\n return False\n" + }, + { + "task_id": "HumanEval/76", + "result": "def is_simple_power(x, n):\n if n <= 1:\n return x == n\n power = 1\n while power < x:\n power *= n\n return power == x\n" + }, + { + "task_id": "HumanEval/77", + "result": "return round(abs(a) ** (1/3)) ** 3 == abs(a)\n" + }, + { + "task_id": "HumanEval/78", + "result": "prime_hex_digits = {'2', '3', '5', '7', 'B', 'D'}\ncount = 0\n\nfor digit in num:\n if digit in prime_hex_digits:\n count += 1\n\nreturn count\n" + }, + { + "task_id": "HumanEval/79", + "result": "def decimal_to_binary(decimal):\n return 'db' + bin(decimal)[2:] + 'db'\n" + }, + { + "task_id": "HumanEval/80", + "result": "def is_happy(s):\n if len(s) < 3:\n return False\n for i in range(len(s) - 2):\n if len(set(s[i:i + 3])) < 3:\n return False\n return True\n" + }, + { + "task_id": "HumanEval/81", + "result": "def numerical_letter_grade(grades):\n letter_grades = []\n for gpa in grades:\n if gpa == 4.0:\n letter_grades.append('A+')\n elif gpa > 3.7:\n letter_grades.append('A')\n elif gpa > 3.3:\n letter_grades.append('A-')\n elif gpa > 3.0:\n letter_grades.append('B+')\n elif gpa > 2.7:\n letter_grades.append('B')\n elif gpa > 2.3:\n letter_grades.append('B-')\n elif gpa > 2.0:\n letter_grades.append('C+')\n elif gpa > 1.7:\n letter_grades.append('C')\n elif gpa > 1.3:\n letter_grades.append('C-')\n elif gpa > 1.0:\n letter_grades.append('D+')\n elif gpa > 0.7:\n letter_grades.append('D')\n elif gpa > 0.0:\n letter_grades.append('D-')\n else:\n letter_grades.append('E')\n return letter_grades\n" + }, + { + "task_id": "HumanEval/82", + "result": "def prime_length(string):\n def is_prime(n):\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n \n length = len(string)\n return is_prime(length)\n" + }, + { + "task_id": "HumanEval/83", + "result": "def starts_one_ends(n):\n if n <= 0:\n return 0\n # Numbers starting with 1\n start_with_1 = 10**(n-1) # 1 followed by (n-1) zeros\n # Numbers ending with 1\n end_with_1 = 10**(n-1)\n\n # Counting overlaps (i.e., numbers that both start and end with 1)\n # These are of the form 1...1, and there are (n-2) digits in between\n overlap_count = 10**(n-2) if n > 1 else 1\n\n return start_with_1 + end_with_1 - overlap_count\n " + }, + { + "task_id": "HumanEval/84", + "result": "def solve(N):\n if not (0 <= N <= 10000):\n raise ValueError(\"N must be between 0 and 10000\")\n\n digit_sum = sum(int(digit) for digit in str(N))\n return bin(digit_sum)[2:]\n" + }, + { + "task_id": "HumanEval/85", + "result": "def add(lst):\n total = 0\n for index, value in enumerate(lst):\n if index % 2 != 0 and value % 2 == 0:\n total += value\n return total\n" + }, + { + "task_id": "HumanEval/86", + "result": "def anti_shuffle(s):\n result = []\n for word in s.split(' '):\n sorted_word = ''.join(sorted(word))\n result.append(sorted_word)\n return ' '.join(result)\n" + }, + { + "task_id": "HumanEval/87", + "result": "coordinates = []\n\nfor row_index, row in enumerate(lst):\n for col_index, value in enumerate(row):\n if value == x:\n coordinates.append((row_index, col_index))\n\ncoordinates.sort(key=lambda coord: (coord[0], -coord[1]))\n\nreturn coordinates\n" + }, + { + "task_id": "HumanEval/88", + "result": "def sort_array(array):\n sum_first_last = array[0] + array[-1] if array else 0\n return sorted(array) if sum_first_last % 2 != 0 else sorted(array, reverse=True)\n" + }, + { + "task_id": "HumanEval/89", + "result": "def encrypt(s):\n result = \"\"\n for char in s:\n if 'a' <= char <= 'z': # Check if char is a lowercase letter\n new_char = chr((ord(char) - ord('a') + 4) % 26 + ord('a'))\n result += new_char\n return result\n" + }, + { + "task_id": "HumanEval/90", + "result": "def next_smallest(lst):\n if not lst:\n return None\n unique_elements = list(set(lst))\n unique_elements.sort()\n if len(unique_elements) < 2:\n return None\n return unique_elements[1]\n" + }, + { + "task_id": "HumanEval/91", + "result": "sentences = [s.strip() for s in re.split(r'[.!?]', S) if s] # Split into sentences\nreturn sum(1 for sentence in sentences if sentence.startswith(\"I\")) # Count \"I\"-starting sentences\n" + }, + { + "task_id": "HumanEval/92", + "result": "def any_int(x, y, z):\n return all(isinstance(i, int) for i in (x, y, z)) and (\n x == y + z or y == x + z or z == x + y\n )\n" + }, + { + "task_id": "HumanEval/93", + "result": "def encode(message):\n vowels = {'a': 'c', 'e': 'g', 'i': 'k', 'o': 'q', 'u': 'w',\n 'A': 'C', 'E': 'G', 'I': 'K', 'O': 'Q', 'U': 'W'}\n \n result = []\n for char in message:\n if char in vowels:\n result.append(vowels[char])\n elif char.isalpha():\n result.append(char.swapcase())\n else:\n result.append(char)\n \n return ''.join(result)\n" + }, + { + "task_id": "HumanEval/94", + "result": "def skjkasdkd(lst):\n def is_prime(n):\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n \n largest_prime = None\n \n for num in lst:\n if is_prime(num):\n if largest_prime is None or num > largest_prime:\n largest_prime = num\n \n if largest_prime is None:\n return 0 # or some other default value if there's no prime\n \n return sum(int(digit) for digit in str(largest_prime))\n" + }, + { + "task_id": "HumanEval/95", + "result": "def check_dict_case(d):\n if not d: # Check if the dictionary is empty\n return False\n \n keys = d.keys() # Get all keys from the dictionary\n all_lower = all(isinstance(k, str) and k.islower() for k in keys) # Check if all keys are lower case\n all_upper = all(isinstance(k, str) and k.isupper() for k in keys) # Check if all keys are upper case\n \n return all_lower or all_upper # Return True if either condition is met\n" + }, + { + "task_id": "HumanEval/96", + "result": "def is_prime(num):\n if num < 2:\n return False\n for i in range(2, int(num**0.5) + 1):\n if num % i == 0:\n return False\n return True\n\ndef count_up_to(n):\n return [i for i in range(2, n) if is_prime(i)]\n" + }, + { + "task_id": "HumanEval/97", + "result": "def multiply(a, b):\n # Get the unit digit of each number\n unit_digit_a = abs(a) % 10\n unit_digit_b = abs(b) % 10\n # Return the product of the unit digits\n return unit_digit_a * unit_digit_b\n " + }, + { + "task_id": "HumanEval/98", + "result": "def count_upper(s):\n count = 0\n for i in range(0, len(s), 2):\n if s[i] in 'AEIOU':\n count += 1\n return count\n " + }, + { + "task_id": "HumanEval/99", + "result": "number = float(value)\n floor_value = int(number) # Get the floor value of the number\n ceil_value = floor_value + 1 # Get the ceiling value\n \n if number - floor_value < 0.5:\n return floor_value\n elif number - floor_value > 0.5:\n return ceil_value\n else: # number - floor_value == 0.5\n return ceil_value if number > 0 else floor_value\n" + }, + { + "task_id": "HumanEval/100", + "result": "def make_a_pile(n):\n stones = []\n current_stones = n\n \n for i in range(n):\n stones.append(current_stones)\n if current_stones % 2 == 0: # current_stones is even\n current_stones += 2 # next level will have the next even number\n else:\n current_stones += 2 # next level will have the next odd number\n \n return stones\n" + }, + { + "task_id": "HumanEval/101", + "result": "import re\n\ndef words_string(s):\n return re.split(r'[ ,]+', s)\n" + }, + { + "task_id": "HumanEval/102", + "result": "def choose_num(x, y):\n lower = min(x, y)\n upper = max(x, y)\n \n for num in range(upper, lower - 1, -1):\n if num % 2 == 0:\n return num\n return -1\n" + }, + { + "task_id": "HumanEval/103", + "result": "def rounded_avg(n, m):\n if n > m:\n return -1\n avg = round((n + m) / 2)\n return bin(avg)\n" + }, + { + "task_id": "HumanEval/104", + "result": "result = []\nfor num in x:\n if all(int(digit) % 2 != 0 for digit in str(num)): # Check if all digits are odd\n result.append(num)\nreturn sorted(result)\n" + }, + { + "task_id": "HumanEval/105", + "result": "def by_length(arr):\n filtered = [x for x in arr if 1 <= x <= 9] # Step 1: Filter numbers\n sorted_arr = sorted(filtered) # Step 2: Sort the array\n reversed_arr = sorted_arr[::-1] # Step 3: Reverse the array\n\n # Step 4: Map integers to their names\n number_names = [\"One\", \"Two\", \"Three\", \"Four\", \"Five\", \"Six\", \"Seven\", \"Eight\", \"Nine\"]\n result = [number_names[x - 1] for x in reversed_arr] # Step 5: Replace with names\n return result\n" + }, + { + "task_id": "HumanEval/106", + "result": "result = []\nfor i in range(1, n + 1):\n if i % 2 == 0: # i is even\n factorial = 1\n for j in range(1, i + 1):\n factorial *= j\n result.append(factorial)\n else: # i is odd\n sum_odd = sum(range(1, i + 1))\n result.append(sum_odd)\nreturn result\n" + }, + { + "task_id": "HumanEval/107", + "result": "def even_odd_palindrome(n):\n def is_palindrome(num):\n return str(num) == str(num)[::-1]\n \n odd_count = 0\n even_count = 0\n \n for i in range(1, n + 1):\n if is_palindrome(i):\n if i % 2 == 0:\n even_count += 1\n else:\n odd_count += 1\n \n return (even_count, odd_count)\n" + }, + { + "task_id": "HumanEval/108", + "result": "def count_nums(arr):\n count = 0\n for num in arr:\n digit_sum = sum(int(digit) if num >= 0 else -int(digit) for digit in str(abs(num)))\n if digit_sum > 0:\n count += 1\n return count\n" + }, + { + "task_id": "HumanEval/109", + "result": "def move_one_ball(arr):\n if not arr:\n return True\n\n descents = 0\n n = len(arr)\n\n for i in range(n):\n if arr[i] > arr[(i + 1) % n]: # Use modulo to wrap around\n descents += 1\n\n return descents <= 1\n" + }, + { + "task_id": "HumanEval/110", + "result": "def exchange(lst1, lst2):\n odd_count = sum(1 for x in lst1 if x % 2 != 0)\n even_count_in_lst2 = sum(1 for x in lst2 if x % 2 == 0)\n if odd_count <= even_count_in_lst2:\n return \"YES\"\n else:\n return \"NO\"\n" + }, + { + "task_id": "HumanEval/111", + "result": "def histogram(test):\n counts = {}\n \n # Split the input string into letters and count occurrences\n for letter in test.split():\n counts[letter] = counts.get(letter, 0) + 1\n \n if not counts:\n return {}\n \n # Find the maximum count\n max_count = max(counts.values())\n \n # Gather all letters with the maximum count\n result = {letter: count for letter, count in counts.items() if count == max_count}\n \n return result\n" + }, + { + "task_id": "HumanEval/112", + "result": "def reverse_delete(s, c):\n result = ''.join(char for char in s if char not in c) # Step 1: Remove characters\n is_palindrome = result == result[::-1] # Step 2: Check for palindrome\n return result, is_palindrome # Step 3: Return result\n" + }, + { + "task_id": "HumanEval/113", + "result": "def odd_count(lst):\n result = []\n for s in lst:\n odd_count = sum(1 for char in s if char in '13579')\n result.append(f\"the number of odd elements {odd_count}n the str{odd_count}ng {odd_count} of the {odd_count}nput.\")\n return result\n" + }, + { + "task_id": "HumanEval/114", + "result": "def minSubArraySum(nums):\n min_sum = float('inf')\n current_sum = 0\n\n for num in nums:\n current_sum += num\n if current_sum < min_sum:\n min_sum = current_sum\n if current_sum > 0:\n current_sum = 0\n\n return min_sum\n" + }, + { + "task_id": "HumanEval/115", + "result": "def max_fill(grid, capacity):\n total_water = 0\n \n # Count total water in the grid\n for row in grid:\n total_water += sum(row)\n \n # Calculate number of times to lower buckets\n return math.ceil(total_water / capacity)\n" + }, + { + "task_id": "HumanEval/116", + "result": "def sort_array(arr):\n arr.sort(key=lambda x: (bin(x).count('1'), x))\n return arr\n" + }, + { + "task_id": "HumanEval/117", + "result": "def select_words(s, n):\n if not s:\n return []\n \n def count_consonants(word):\n consonants = \"bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ\"\n return sum(1 for char in word if char in consonants)\n \n words = s.split()\n result = [word for word in words if count_consonants(word) == n]\n \n return result\n" + }, + { + "task_id": "HumanEval/118", + "result": "def get_closest_vowel(word):\n vowels = 'aeiouAEIOU'\n last_consonants = []\n \n # Traverse the string from right to left\n for char in reversed(word):\n if char in vowels:\n # Check for vowels between two consonants\n if len(last_consonants) == 2:\n return char\n elif char.isalpha(): # It is a consonant\n last_consonants.append(char)\n # Keep only the last two consonants\n if len(last_consonants) > 2:\n last_consonants.pop(0)\n\n return \"\"\n" + }, + { + "task_id": "HumanEval/119", + "result": "def match_parens(lst):\n s1, s2 = lst\n\n def is_balanced(s1, s2):\n count = 0\n for char in s1 + s2:\n if char == '(':\n count += 1\n else:\n count -= 1\n if count < 0:\n return False\n return count == 0\n\n return 'Yes' if is_balanced(s1, s2) or is_balanced(s2, s1) else 'No'\n" + }, + { + "task_id": "HumanEval/120", + "result": "def maximum(arr, k):\n return sorted(sorted(arr)[-k:])\n" + }, + { + "task_id": "HumanEval/121", + "result": "total_sum = sum(lst[i] for i in range(len(lst)) if i % 2 == 0 and lst[i] % 2 != 0)\nreturn total_sum\n" + }, + { + "task_id": "HumanEval/122", + "result": "def add_elements(arr, k):\n return sum(x for x in arr[:k] if -10 < x < 100)\n " + }, + { + "task_id": "HumanEval/123", + "result": "def get_odd_collatz(n):\n odd_numbers = []\n \n while n != 1:\n if n % 2 != 0: # n is odd\n odd_numbers.append(n)\n n = n // 2 if n % 2 == 0 else 3 * n + 1\n \n odd_numbers.append(1) # Append 1 as it's also considered odd\n return sorted(odd_numbers)\n" + }, + { + "task_id": "HumanEval/124", + "result": "def valid_date(date):\n if not date:\n return False\n \n if date.count('-') != 2:\n return False\n \n month, day, year = date.split('-')\n \n try:\n month = int(month)\n day = int(day)\n year = int(year)\n except ValueError:\n return False\n \n if month < 1 or month > 12:\n return False\n \n if month in [1, 3, 5, 7, 8, 10, 12]:\n if day < 1 or day > 31:\n return False\n elif month in [4, 6, 9, 11]:\n if day < 1 or day > 30:\n return False\n elif month == 2:\n if day < 1 or day > 29:\n return False\n \n return True\n" + }, + { + "task_id": "HumanEval/125", + "result": "def split_words(txt):\n if any(char.isspace() for char in txt):\n return txt.split()\n elif ',' in txt:\n return txt.split(',')\n else:\n return sum(1 for char in txt if char.islower() and (ord(char) - ord('a')) % 2 == 0)\n" + }, + { + "task_id": "HumanEval/126", + "result": "def is_sorted(lst):\n return lst == sorted(lst) and len(lst) == len(set(lst))\n" + }, + { + "task_id": "HumanEval/127", + "result": "def intersection(interval1, interval2):\n start1, end1 = interval1\n start2, end2 = interval2\n\n # Calculate the intersection\n start_intersection = max(start1, start2)\n end_intersection = min(end1, end2)\n\n # Check if there is an intersection\n if start_intersection >= end_intersection:\n return \"NO\"\n\n # Calculate length of the intersection\n length = end_intersection - start_intersection\n\n # Function to check if a number is prime\n def is_prime(n):\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n\n # Check if the length of the intersection is prime\n if is_prime(length):\n return \"YES\"\n else:\n return \"NO\"\n" + }, + { + "task_id": "HumanEval/128", + "result": "def prod_signs(arr):\n if not arr:\n return None\n \n product_of_signs = 1\n sum_of_magnitudes = 0\n \n for num in arr:\n if num > 0:\n sum_of_magnitudes += num\n elif num < 0:\n sum_of_magnitudes += -num\n product_of_signs *= -1\n else: # num == 0\n product_of_signs = 0\n \n return sum_of_magnitudes * product_of_signs\n" + }, + { + "task_id": "HumanEval/129", + "result": "def minPath(grid, k):\n from itertools import product\n \n n = len(grid)\n best_path = []\n\n def dfs(r, c, path):\n nonlocal best_path\n \n if len(path) == k:\n if not best_path or path < best_path:\n best_path = path[:]\n return\n \n directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]\n for dr, dc in directions:\n nr, nc = r + dr, c + dc\n if 0 <= nr < n and 0 <= nc < n:\n path.append(grid[nr][nc])\n dfs(nr, nc, path)\n path.pop()\n\n for i, j in product(range(n), repeat=2):\n dfs(i, j, [grid[i][j]])\n\n return best_path\n" + }, + { + "task_id": "HumanEval/130", + "result": "def tri(n):\n tribonacci = []\n \n for i in range(n + 1):\n if i == 0:\n tribonacci.append(1)\n elif i == 1:\n tribonacci.append(3)\n elif i % 2 == 0: # Even\n tribonacci.append(1 + i / 2)\n else: # Odd\n tribonacci.append(\n tribonacci[i - 1] + tribonacci[i - 2] + tribonacci[i + 1] if (i + 1 <= n) else tribonacci[i - 1] + tribonacci[i - 2]\n )\n \n return tribonacci\n" + }, + { + "task_id": "HumanEval/131", + "result": "def digits(n):\n product = 1\n has_odd = False\n while n > 0:\n digit = n % 10\n if digit % 2 != 0: # Check if the digit is odd\n product *= digit\n has_odd = True\n n //= 10 # Remove the last digit\n return product if has_odd else 0\n " + }, + { + "task_id": "HumanEval/132", + "result": "def is_nested(string):\n stack = []\n nested = False\n\n for char in string:\n if char == '[':\n stack.append(char)\n elif char == ']':\n if stack:\n top = stack.pop()\n if stack: # Check if there are still brackets in the stack\n nested = True # We found a nested bracket\n else:\n return False # More closing brackets than opening\n\n # If there are still items in stack, that means we have unmatched opening brackets\n return nested\n\n# Example tests\nprint(is_nested('[[]]')) # ➞ True\nprint(is_nested('[]]]]]]][[[[[]')) # ➞ False\nprint(is_nested('[][]')) # ➞ False\nprint(is_nested('[]')) # ➞ False\nprint(is_nested('[[][]]')) # ➞ True\nprint(is_nested('[[]][[')) # ➞ True\n" + }, + { + "task_id": "HumanEval/133", + "result": "import math\n\ndef sum_squares(lst):\n return sum(math.ceil(x) ** 2 for x in lst)\n" + }, + { + "task_id": "HumanEval/134", + "result": "def check_if_last_char_is_a_letter(txt):\n txt = txt.rstrip() # Remove trailing spaces\n if len(txt) == 0: # Check if the string is empty\n return False\n last_char = txt[-1] # Get the last character\n\n # Check if last_char is a letter and is not part of a word\n return last_char.isalpha() and (len(txt) == 1 or txt[-2] == ' ')\n" + }, + { + "task_id": "HumanEval/135", + "result": "for i in range(1, len(arr)):\n if arr[i] < arr[i - 1]:\n return i\n return -1\n" + }, + { + "task_id": "HumanEval/136", + "result": "largest_smallest_integers(lst):\n largest_negative = None\n smallest_positive = None\n \n for number in lst:\n if number < 0:\n if largest_negative is None or number > largest_negative:\n largest_negative = number\n elif number > 0:\n if smallest_positive is None or number < smallest_positive:\n smallest_positive = number\n\n return (largest_negative, smallest_positive)\n" + }, + { + "task_id": "HumanEval/137", + "result": "def compare_one(a, b):\n def to_float(value):\n if isinstance(value, str):\n value = value.replace(',', '.') \n return float(value)\n\n try:\n float_a = to_float(a)\n float_b = to_float(b)\n except ValueError:\n return None\n\n if float_a > float_b:\n return a\n elif float_a < float_b:\n return b\n else:\n return None\n" + }, + { + "task_id": "HumanEval/138", + "result": "def is_equal_to_sum_even(n):\n return n >= 8 and n % 2 == 0\n" + }, + { + "task_id": "HumanEval/139", + "result": "def special_factorial(n):\n def factorial(x):\n if x == 0 or x == 1:\n return 1\n else:\n result = 1\n for i in range(2, x + 1):\n result *= i\n return result\n\n result = 1\n for i in range(1, n + 1):\n result *= factorial(i)\n \n return result\n" + }, + { + "task_id": "HumanEval/140", + "result": "def fix_spaces(text):\n import re\n text = text.lstrip(' ')\n text = re.sub(r' {2,}', '-', text)\n text = text.replace(' ', '_')\n if text.startswith('_'):\n text = '_' + text.strip('_')\n return text\n" + }, + { + "task_id": "HumanEval/141", + "result": "def file_name_check(file_name):\n # Check for one dot\n if file_name.count('.') != 1:\n return 'No'\n \n # Split the name into the part before and after the dot\n name_part, ext_part = file_name.split('.')\n \n # Check if the name part is empty and starts with a letter\n if not name_part or not name_part[0].isalpha():\n return 'No'\n \n # Check for valid file extensions\n valid_extensions = ['txt', 'exe', 'dll']\n if ext_part not in valid_extensions:\n return 'No'\n \n # Count the digits in the file name\n digit_count = sum(c.isdigit() for c in file_name)\n if digit_count > 3:\n return 'No'\n \n return 'Yes'\n" + }, + { + "task_id": "HumanEval/142", + "result": "def sum_squares(lst):\n total_sum = 0\n for index, value in enumerate(lst):\n if index % 3 == 0:\n total_sum += value ** 2\n elif index % 4 == 0:\n total_sum += value ** 3\n else:\n total_sum += value\n return total_sum\n" + }, + { + "task_id": "HumanEval/143", + "result": "def words_in_sentence(sentence):\n def is_prime(n):\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n\n words = sentence.split()\n prime_length_words = [word for word in words if is_prime(len(word))]\n return ' '.join(prime_length_words)\n" + }, + { + "task_id": "HumanEval/144", + "result": "def simplify(x, n):\n num1, denom1 = map(int, x.split('/'))\n num2, denom2 = map(int, n.split('/'))\n \n result_numerator = num1 * num2\n result_denominator = denom1 * denom2\n \n return result_numerator % result_denominator == 0\n" + }, + { + "task_id": "HumanEval/145", + "result": "def order_by_points(nums):\n def sum_of_digits(n):\n return sum(int(digit) for digit in str(abs(n)))\n\n return sorted(nums, key=lambda x: (sum_of_digits(x), nums.index(x)))\n" + }, + { + "task_id": "HumanEval/146", + "result": "def specialFilter(nums):\n count = 0\n for num in nums:\n if num > 10:\n num_str = str(num)\n first_digit = int(num_str[0])\n last_digit = int(num_str[-1])\n if first_digit % 2 != 0 and last_digit % 2 != 0:\n count += 1\n return count\n" + }, + { + "task_id": "HumanEval/147", + "result": "a = [i * i - i + 1 for i in range(1, n + 1)]\ncount = 0\n\n# Iterate through all possible triples\nfor i in range(n):\n for j in range(i + 1, n):\n for k in range(j + 1, n):\n if (a[i] + a[j] + a[k]) % 3 == 0:\n count += 1\n \nreturn count\n" + }, + { + "task_id": "HumanEval/148", + "result": "def bf(planet1, planet2):\n planets = [\"Mercury\", \"Venus\", \"Earth\", \"Mars\", \"Jupiter\", \"Saturn\", \"Uranus\", \"Neptune\"]\n if planet1 not in planets or planet2 not in planets:\n return ()\n \n index1 = planets.index(planet1)\n index2 = planets.index(planet2)\n \n if index1 > index2:\n index1, index2 = index2, index1\n \n return tuple(planets[index1 + 1:index2])\n" + }, + { + "task_id": "HumanEval/149", + "result": "def sorted_list_sum(lst):\n # Remove strings with odd lengths\n filtered = [s for s in lst if len(s) % 2 == 0]\n # Sort by length and then alphabetically\n sorted_list = sorted(filtered, key=lambda x: (len(x), x))\n return sorted_list\n" + }, + { + "task_id": "HumanEval/150", + "result": "def x_or_y(n, x, y):\n def is_prime(num):\n if num <= 1:\n return False\n for i in range(2, int(num**0.5) + 1):\n if num % i == 0:\n return False\n return True\n \n return x if is_prime(n) else y\n" + }, + { + "task_id": "HumanEval/151", + "result": "def double_the_difference(lst):\n odd_squares_sum = sum(x ** 2 for x in lst if x >= 0 and x % 2 == 1)\n return odd_squares_sum\n" + }, + { + "task_id": "HumanEval/152", + "result": "def compare(game, guess):\n return [abs(g - s) for g, s in zip(guess, game)]\n" + }, + { + "task_id": "HumanEval/153", + "result": "def Strongest_Extension(class_name, extensions):\n strongest_extension = \"\"\n max_strength = float('-inf') # Initialize to negative infinity to find the max\n\n for extension in extensions:\n CAP = sum(1 for char in extension if char.isupper())\n SM = sum(1 for char in extension if char.islower())\n strength = CAP - SM\n \n if strength > max_strength: # Update if this extension is stronger\n max_strength = strength\n strongest_extension = extension\n\n return f\"{class_name}.{strongest_extension}\"\n" + }, + { + "task_id": "HumanEval/154", + "result": "def cycpattern_check(a, b):\n if len(b) == 0:\n return True\n return any(b[i:i+len(b)] in a for i in range(len(b)))\n" + }, + { + "task_id": "HumanEval/155", + "result": "even_count = 0\n odd_count = 0\n\n for digit in str(abs(num)):\n if int(digit) % 2 == 0:\n even_count += 1\n else:\n odd_count += 1\n\n return (even_count, odd_count)\n" + }, + { + "task_id": "HumanEval/156", + "result": "def int_to_mini_roman(number):\n roman_numerals = [\n (1000, 'm'), (900, 'cm'), (500, 'd'), (400, 'cd'),\n (100, 'c'), (90, 'xc'), (50, 'l'), (40, 'xl'),\n (10, 'x'), (9, 'ix'), (5, 'v'), (4, 'iv'), (1, 'i')\n ]\n \n result = \"\"\n \n for value, numeral in roman_numerals:\n while number >= value:\n result += numeral\n number -= value\n \n return result\n" + }, + { + "task_id": "HumanEval/157", + "result": "sides = sorted([a, b, c])\nreturn sides[0]**2 + sides[1]**2 == sides[2]**2\n" + }, + { + "task_id": "HumanEval/158", + "result": "def find_max(words):\n max_word = \"\"\n max_unique_count = 0\n \n for word in words:\n unique_chars = len(set(word))\n \n if (unique_chars > max_unique_count or \n (unique_chars == max_unique_count and word < max_word)):\n max_word = word\n max_unique_count = unique_chars\n \n return max_word\n" + }, + { + "task_id": "HumanEval/159", + "result": "def eat(number, need, remaining):\n total_eaten = number\n if need <= remaining:\n total_eaten += need\n remaining -= need\n else:\n total_eaten += remaining\n remaining = 0\n return [total_eaten, remaining]\n" + }, + { + "task_id": "HumanEval/160", + "result": "def do_algebra(operator, operand):\n result = operand[0]\n for i in range(len(operator)):\n if operator[i] == '+':\n result += operand[i + 1]\n elif operator[i] == '-':\n result -= operand[i + 1]\n elif operator[i] == '*':\n result *= operand[i + 1]\n elif operator[i] == '//':\n result //= operand[i + 1]\n elif operator[i] == '**':\n result **= operand[i + 1]\n return result\n" + }, + { + "task_id": "HumanEval/161", + "result": "def solve(s):\n # Check if there are any letters in the input string\n has_letter = any(c.isalpha() for c in s)\n\n if not has_letter:\n # Reverse the string if no letters are present\n return s[::-1]\n else:\n # Create a list to hold the new characters\n result = []\n # Iterate through each character in the string\n for c in s:\n if c.isalpha():\n # Reverse case for letters\n if c.islower():\n result.append(c.upper())\n else:\n result.append(c.lower())\n else:\n # Keep non-letter characters as they are\n result.append(c)\n return ''.join(result)\n " + }, + { + "task_id": "HumanEval/162", + "result": "import hashlib\n\ndef string_to_md5(text):\n if text == \"\":\n return None\n hash_object = hashlib.md5(text.encode())\n return hash_object.hexdigest()\n" + }, + { + "task_id": "HumanEval/163", + "result": "def generate_integers(a, b):\n lower = min(a, b)\n upper = max(a, b)\n return [n for n in range(lower, upper + 1) if n % 2 == 0]\n" + } +] \ No newline at end of file diff --git a/experiment/humaneval/interpreter_prediction.jsonl b/experiment/humaneval/interpreter_prediction.jsonl new file mode 100644 index 000000000..c7ba7a0c0 --- /dev/null +++ b/experiment/humaneval/interpreter_prediction.jsonl @@ -0,0 +1,164 @@ +{"task_id": "HumanEval/0", "completion": "for i in range(len(numbers)):\n for j in range(i + 1, len(numbers)):\n if abs(numbers[i] - numbers[j]) < threshold:\n return True\n return False\n"} +{"task_id": "HumanEval/1", "completion": "def separate_paren_groups(paren_string: str) -> List[str]:\n paren_string = paren_string.replace(\" \", \"\") # Step 1: Remove spaces\n result = []\n stack = []\n current_group = []\n\n for char in paren_string:\n if char == '(':\n if not stack: # Starting a new group\n current_group = [] # Reset current group\n stack.append(char)\n current_group.append(char) # Add to current group\n elif char == ')':\n stack.pop()\n current_group.append(char) # Add to current group\n if not stack: # If stack is empty, a complete group is found\n result.append(''.join(current_group)) # Add to result\n\n return result\n"} +{"task_id": "HumanEval/2", "completion": "def truncate_number(number: float) -> float:\n return number - int(number)\n"} +{"task_id": "HumanEval/3", "completion": "def below_zero(operations: List[int]) -> bool:\n balance = 0\n for operation in operations:\n balance += operation\n if balance < 0:\n return True\n return False\n"} +{"task_id": "HumanEval/4", "completion": "mean_value = sum(numbers) / len(numbers) # Calculate mean\ndeviations = [abs(x - mean_value) for x in numbers] # Calculate absolute differences\nreturn sum(deviations) / len(deviations) # Calculate and return MAD\n"} +{"task_id": "HumanEval/5", "completion": "def intersperse(numbers: List[int], delimeter: int) -> List[int]:\n if not numbers:\n return []\n \n result = []\n for i in range(len(numbers)):\n result.append(numbers[i])\n if i < len(numbers) - 1: # Don't add delimeter after the last element\n result.append(delimeter)\n \n return result\n"} +{"task_id": "HumanEval/6", "completion": "def parse_nested_parens(paren_string: str) -> List[int]:\n depths = []\n groups = paren_string.split()\n\n for group in groups:\n max_depth = 0\n current_depth = 0\n \n for char in group:\n if char == '(':\n current_depth += 1\n max_depth = max(max_depth, current_depth)\n elif char == ')':\n current_depth -= 1\n \n depths.append(max_depth)\n\n return depths\n"} +{"task_id": "HumanEval/7", "completion": "return [s for s in strings if substring in s]\n"} +{"task_id": "HumanEval/8", "completion": "def sum_product(numbers: List[int]) -> Tuple[int, int]:\n total_sum = sum(numbers)\n total_product = 1\n for number in numbers:\n total_product *= number\n return total_sum, total_product\n"} +{"task_id": "HumanEval/9", "completion": "def rolling_max(numbers: List[int]) -> List[int]:\n max_so_far = float('-inf')\n rolling_max_list = []\n\n for number in numbers:\n if number > max_so_far:\n max_so_far = number\n rolling_max_list.append(max_so_far)\n\n return rolling_max_list\n"} +{"task_id": "HumanEval/10", "completion": "def make_palindrome(string: str) -> str:\n def is_palindrome(s: str) -> bool:\n return s == s[::-1]\n\n for i in range(len(string)):\n if is_palindrome(string[i:]):\n return string + string[:i][::-1]\n \n return string\n"} +{"task_id": "HumanEval/11", "completion": "result = ''.join(str(int(x) ^ int(y)) for x, y in zip(a, b))\n"} +{"task_id": "HumanEval/12", "completion": "def longest(strings: List[str]) -> Optional[str]:\n if not strings:\n return None\n longest_string = \"\"\n for string in strings:\n if len(string) > len(longest_string):\n longest_string = string\n return longest_string\n"} +{"task_id": "HumanEval/13", "completion": "def greatest_common_divisor(a: int, b: int) -> int:\n while b:\n a, b = b, a % b\n return a\n"} +{"task_id": "HumanEval/14", "completion": "return [string[:i] for i in range(1, len(string) + 1)]\n"} +{"task_id": "HumanEval/15", "completion": "return ' '.join(str(i) for i in range(n + 1))\n"} +{"task_id": "HumanEval/16", "completion": "return len(set(string.lower()))\n"} +{"task_id": "HumanEval/17", "completion": "def parse_music(music_string: str) -> List[int]:\n note_duration_map = {\n 'o': 4,\n 'o|': 2,\n '.|': 1\n }\n \n notes = music_string.split()\n durations = [note_duration_map[note] for note in notes]\n \n return durations\n"} +{"task_id": "HumanEval/18", "completion": "def how_many_times(string: str, substring: str) -> int:\n count = 0\n start = 0\n\n while True:\n start = string.find(substring, start)\n if start == -1:\n break\n count += 1\n start += 1 # Move to the next character to allow for overlapping\n\n return count\n"} +{"task_id": "HumanEval/19", "completion": "def sort_numbers(numbers: str) -> str:\n number_map = {\n 'zero': 0,\n 'one': 1,\n 'two': 2,\n 'three': 3,\n 'four': 4,\n 'five': 5,\n 'six': 6,\n 'seven': 7,\n 'eight': 8,\n 'nine': 9\n }\n \n words = numbers.split()\n sorted_numbers = sorted(words, key=lambda x: number_map[x])\n return ' '.join(sorted_numbers)\n"} +{"task_id": "HumanEval/20", "completion": "def find_closest_elements(numbers: List[float]) -> Tuple[float, float]:\n numbers.sort()\n closest_pair = (numbers[0], numbers[1])\n min_diff = abs(numbers[1] - numbers[0])\n \n for i in range(1, len(numbers) - 1):\n diff = abs(numbers[i + 1] - numbers[i])\n if diff < min_diff:\n min_diff = diff\n closest_pair = (numbers[i], numbers[i + 1])\n \n return closest_pair\n"} +{"task_id": "HumanEval/21", "completion": "return [(num - min_val) / (max_val - min_val) for num in numbers]\n"} +{"task_id": "HumanEval/22", "completion": "return [value for value in values if isinstance(value, int)]\n"} +{"task_id": "HumanEval/23", "completion": "return len(string)\n"} +{"task_id": "HumanEval/24", "completion": "for i in range(n - 1, 0, -1):\n if n % i == 0:\n return i\n"} +{"task_id": "HumanEval/25", "completion": "def factorize(n: int) -> List[int]:\n factors = []\n while n % 2 == 0:\n factors.append(2)\n n //= 2\n for i in range(3, int(n**0.5) + 1, 2):\n while n % i == 0:\n factors.append(i)\n n //= i\n if n > 2:\n factors.append(n)\n return factors\n"} +{"task_id": "HumanEval/26", "completion": "def remove_duplicates(numbers: List[int]) -> List[int]:\n counts = {}\n for number in numbers:\n counts[number] = counts.get(number, 0) + 1\n \n return [number for number in numbers if counts[number] == 1]\n"} +{"task_id": "HumanEval/27", "completion": "return string.swapcase()\n"} +{"task_id": "HumanEval/28", "completion": "def concatenate(strings: List[str]) -> str:\n return ''.join(strings)\n"} +{"task_id": "HumanEval/29", "completion": "def filter_by_prefix(strings: List[str], prefix: str) -> List[str]:\n return [s for s in strings if s.startswith(prefix)]\n"} +{"task_id": "HumanEval/30", "completion": "def get_positive(l: list):\n return [num for num in l if num > 0]\n"} +{"task_id": "HumanEval/31", "completion": "def is_prime(n):\n if n < 2:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n"} +{"task_id": "HumanEval/32", "completion": "def find_zero(xs: list):\n \"\"\" xs are coefficients of a polynomial. \n find_zero finds x such that poly(x) = 0.\n \"\"\"\n # Contains the polynomial function\n def poly_derivative(xs, x):\n \"\"\" Evaluates the derivative of polynomial with coefficients xs at point x. \"\"\"\n return sum([i * coeff * math.pow(x, i - 1) for i, coeff in enumerate(xs) if i > 0])\n\n # Starting guess can be 0\n x0 = 0.0\n tolerance = 1e-7\n max_iterations = 1000\n for _ in range(max_iterations):\n fx = poly(xs, x0)\n dfx = poly_derivative(xs, x0)\n \n if dfx == 0: # Prevent division by zero\n break\n \n x1 = x0 - fx / dfx\n if abs(x1 - x0) < tolerance: # Check for convergence\n return x1\n x0 = x1\n \n return x0 # Return the last approximation\n"} +{"task_id": "HumanEval/33", "completion": "def sort_third(l: list):\n sorted_third = sorted(l[i] for i in range(len(l)) if i % 3 == 0)\n \n result = l[:]\n j = 0\n for i in range(len(l)):\n if i % 3 == 0:\n result[i] = sorted_third[j]\n j += 1\n\n return result\n"} +{"task_id": "HumanEval/34", "completion": "return sorted(set(l))\n"} +{"task_id": "HumanEval/35", "completion": "def max_element(l: list):\n return max(l)\n"} +{"task_id": "HumanEval/36", "completion": "count = 0\nfor i in range(n):\n if i % 11 == 0 or i % 13 == 0:\n count += str(i).count('7')\nreturn count\n"} +{"task_id": "HumanEval/37", "completion": "def sort_even(l: list):\n even_indices = sorted(l[i] for i in range(0, len(l), 2))\n result = []\n even_index = 0\n for i in range(len(l)):\n if i % 2 == 0:\n result.append(even_indices[even_index])\n even_index += 1\n else:\n result.append(l[i])\n return result\n"} +{"task_id": "HumanEval/38", "completion": "groups = [s[(3 * i):min((3 * i + 3), len(s))] for i in range((len(s) + 2) // 3)]\n groups = [(group[-1] + group[:-1]) if len(group) == 3 else group for group in groups]\n return \"\".join(groups)\n"} +{"task_id": "HumanEval/39", "completion": "def is_prime(num):\n if num < 2:\n return False\n for i in range(2, int(num**0.5) + 1):\n if num % i == 0:\n return False\n return True\n\ndef prime_fib(n: int):\n fib1, fib2 = 0, 1\n prime_fib_count = 0\n current_prime_fib = None\n\n while prime_fib_count < n:\n fib1, fib2 = fib2, fib1 + fib2\n if is_prime(fib2):\n prime_fib_count += 1\n current_prime_fib = fib2\n\n return current_prime_fib\n"} +{"task_id": "HumanEval/40", "completion": "def triples_sum_to_zero(l):\n n = len(l)\n for i in range(n):\n s = set()\n current_sum = -l[i]\n for j in range(i + 1, n):\n if (current_sum - l[j]) in s:\n return True\n s.add(l[j])\n return False\n"} +{"task_id": "HumanEval/41", "completion": "def car_race_collision(n: int) -> int:\n return n * n\n"} +{"task_id": "HumanEval/42", "completion": "def incr_list(l):\n return [x + 1 for x in l]\n"} +{"task_id": "HumanEval/43", "completion": "def pairs_sum_to_zero(l):\n seen = set()\n for num in l:\n if -num in seen:\n return True\n seen.add(num)\n return False\n"} +{"task_id": "HumanEval/44", "completion": "result = \"\"\n while x > 0:\n remainder = x % base\n result = str(remainder) + result # Prepend remainder to the result\n x //= base # Divide x by base\n return result if result else \"0\" # Handle case where x is 0\n"} +{"task_id": "HumanEval/45", "completion": "def triangle_area(a, h):\n return 0.5 * a * h\n"} +{"task_id": "HumanEval/46", "completion": "def fib4(n: int) -> int:\n if n == 0:\n return 0\n elif n == 1:\n return 0\n elif n == 2:\n return 2\n elif n == 3:\n return 0\n\n fib_sequence = [0, 0, 2, 0]\n for i in range(4, n + 1):\n next_value = fib_sequence[-1] + fib_sequence[-2] + fib_sequence[-3] + fib_sequence[-4]\n fib_sequence.append(next_value)\n\n return fib_sequence[n]\n"} +{"task_id": "HumanEval/47", "completion": "l.sort()\n n = len(l)\n if n % 2 == 1: # odd length\n return l[n // 2]\n else: # even length\n return (l[n // 2 - 1] + l[n // 2]) / 2\n"} +{"task_id": "HumanEval/48", "completion": "return text == text[::-1]\n"} +{"task_id": "HumanEval/49", "completion": "return pow(2, n, p)\n"} +{"task_id": "HumanEval/50", "completion": "def decode_shift(s: str):\n return \"\".join([chr(((ord(ch) - 5 - ord(\"a\")) % 26) + ord(\"a\")) for ch in s])\n"} +{"task_id": "HumanEval/51", "completion": "def remove_vowels(text):\n vowels = \"aeiouAEIOU\"\n return ''.join([char for char in text if char not in vowels])\n"} +{"task_id": "HumanEval/52", "completion": "for number in l:\n if number >= t:\n return False\nreturn True\n"} +{"task_id": "HumanEval/53", "completion": "return x + y\n"} +{"task_id": "HumanEval/54", "completion": "return set(s0) == set(s1)\n"} +{"task_id": "HumanEval/55", "completion": "if n == 1 or n == 2:\n return 1\n a, b = 1, 1\n for _ in range(3, n + 1):\n a, b = b, a + b\n return b\n"} +{"task_id": "HumanEval/56", "completion": "def correct_bracketing(brackets: str):\n count = 0\n for char in brackets:\n if char == \"<\":\n count += 1\n elif char == \">\":\n count -= 1\n if count < 0:\n return False\n return count == 0\n"} +{"task_id": "HumanEval/57", "completion": "def monotonic(l: list):\n if len(l) <= 1:\n return True\n\n increasing = decreasing = True\n\n for i in range(1, len(l)):\n if l[i] > l[i - 1]:\n decreasing = False\n elif l[i] < l[i - 1]:\n increasing = False\n\n return increasing or decreasing\n"} +{"task_id": "HumanEval/58", "completion": "def common(l1: list, l2: list):\n return sorted(set(l1) & set(l2))\n"} +{"task_id": "HumanEval/59", "completion": "def largest_prime_factor(n):\n largest_factor = 1\n # Check for number of 2s that divide n\n while n % 2 == 0:\n largest_factor = 2\n n //= 2\n \n # n must be odd at this point, thus check for odd factors from 3\n for i in range(3, int(n**0.5) + 1, 2):\n while n % i == 0:\n largest_factor = i\n n //= i\n \n # This condition is to check if n is a prime number\n # greater than 2\n if n > 2:\n largest_factor = n\n \n return largest_factor\n"} +{"task_id": "HumanEval/60", "completion": "def sum_to_n(n: int):\n return n * (n + 1) // 2\n"} +{"task_id": "HumanEval/61", "completion": "def correct_bracketing(brackets: str) -> bool:\n counter = 0\n for char in brackets:\n if char == '(':\n counter += 1\n elif char == ')':\n counter -= 1\n if counter < 0:\n return False\n return counter == 0\n"} +{"task_id": "HumanEval/62", "completion": "def derivative(xs):\n return [i * xs[i] for i in range(1, len(xs))]\n"} +{"task_id": "HumanEval/63", "completion": "def fibfib(n: int, memo={0: 0, 1: 0, 2: 1}):\n if n in memo:\n return memo[n]\n memo[n] = fibfib(n-1, memo) + fibfib(n-2, memo) + fibfib(n-3, memo)\n return memo[n]\n"} +{"task_id": "HumanEval/64", "completion": "def vowels_count(s):\n count = 0\n vowels = 'aeiou'\n \n for i, char in enumerate(s.lower()):\n if char in vowels or (char == 'y' and i == len(s) - 1):\n count += 1\n \n return count\n"} +{"task_id": "HumanEval/65", "completion": "def circular_shift(x, shift):\n s = str(x)\n length = len(s)\n \n if shift > length:\n return s[::-1]\n \n shift = shift % length\n return s[-shift:] + s[:-shift]\n"} +{"task_id": "HumanEval/66", "completion": "def digitSum(s):\n return sum(ord(char) for char in s if char.isupper())\n "} +{"task_id": "HumanEval/67", "completion": "def fruit_distribution(s, n):\n apples = int(s.split()[0]) \n oranges = int(s.split()[3]) \n \n mangoes = n - apples - oranges\n return mangoes\n"} +{"task_id": "HumanEval/68", "completion": "def pluck(arr):\n smallest_even = float('inf')\n smallest_index = -1\n \n for index, value in enumerate(arr):\n if value % 2 == 0: # Check if the value is even\n if value < smallest_even: # Check if it's the smallest even value\n smallest_even = value\n smallest_index = index\n\n if smallest_index == -1: # No even numbers found\n return []\n \n return [smallest_even, smallest_index]\n"} +{"task_id": "HumanEval/69", "completion": "def search(lst):\n frequency = {}\n \n # Count frequency of each number\n for num in lst:\n if num in frequency:\n frequency[num] += 1\n else:\n frequency[num] = 1\n\n # Check for the greatest integer that meets the condition\n for num in sorted(frequency.keys(), reverse=True):\n if frequency[num] >= num:\n return num\n \n return -1\n"} +{"task_id": "HumanEval/70", "completion": "def strange_sort_list(lst):\n lst.sort()\n result = []\n min_ptr, max_ptr = 0, len(lst) - 1\n \n while min_ptr <= max_ptr:\n if min_ptr == max_ptr:\n result.append(lst[min_ptr])\n else:\n result.append(lst[min_ptr])\n result.append(lst[max_ptr])\n \n min_ptr += 1\n max_ptr -= 1\n \n return result\n"} +{"task_id": "HumanEval/71", "completion": "def triangle_area(a, b, c):\n if a + b > c and a + c > b and b + c > a: # Check validity\n s = (a + b + c) / 2 # Semi-perimeter\n area = (s * (s - a) * (s - b) * (s - c)) ** 0.5 # Heron's formula\n return round(area, 2) # Return area rounded to 2 decimal points\n return -1 # Not a valid triangle\n"} +{"task_id": "HumanEval/72", "completion": "def will_it_fly(q, w):\n return q == q[::-1] and sum(q) <= w\n"} +{"task_id": "HumanEval/73", "completion": "def smallest_change(arr):\n changes = 0\n n = len(arr)\n \n for i in range(n // 2):\n if arr[i] != arr[n - 1 - i]:\n changes += 1\n \n return changes\n"} +{"task_id": "HumanEval/74", "completion": "def total_match(lst1, lst2):\n total_chars_lst1 = sum(len(s) for s in lst1)\n total_chars_lst2 = sum(len(s) for s in lst2)\n\n if total_chars_lst1 < total_chars_lst2:\n return lst1\n elif total_chars_lst1 > total_chars_lst2:\n return lst2\n else:\n return lst1\n"} +{"task_id": "HumanEval/75", "completion": "def is_multiply_prime(a):\n primes = [prime(i) for i in range(1, 30) if prime(i) < 100]\n for combo in combinations(primes, 3):\n if combo[0] * combo[1] * combo[2] == a:\n return True\n return False\n"} +{"task_id": "HumanEval/76", "completion": "def is_simple_power(x, n):\n if n <= 1:\n return x == n\n power = 1\n while power < x:\n power *= n\n return power == x\n"} +{"task_id": "HumanEval/77", "completion": "return round(abs(a) ** (1/3)) ** 3 == abs(a)\n"} +{"task_id": "HumanEval/78", "completion": "prime_hex_digits = {'2', '3', '5', '7', 'B', 'D'}\ncount = 0\n\nfor digit in num:\n if digit in prime_hex_digits:\n count += 1\n\nreturn count\n"} +{"task_id": "HumanEval/79", "completion": "def decimal_to_binary(decimal):\n return 'db' + bin(decimal)[2:] + 'db'\n"} +{"task_id": "HumanEval/80", "completion": "def is_happy(s):\n if len(s) < 3:\n return False\n for i in range(len(s) - 2):\n if len(set(s[i:i + 3])) < 3:\n return False\n return True\n"} +{"task_id": "HumanEval/81", "completion": "def numerical_letter_grade(grades):\n letter_grades = []\n for gpa in grades:\n if gpa == 4.0:\n letter_grades.append('A+')\n elif gpa > 3.7:\n letter_grades.append('A')\n elif gpa > 3.3:\n letter_grades.append('A-')\n elif gpa > 3.0:\n letter_grades.append('B+')\n elif gpa > 2.7:\n letter_grades.append('B')\n elif gpa > 2.3:\n letter_grades.append('B-')\n elif gpa > 2.0:\n letter_grades.append('C+')\n elif gpa > 1.7:\n letter_grades.append('C')\n elif gpa > 1.3:\n letter_grades.append('C-')\n elif gpa > 1.0:\n letter_grades.append('D+')\n elif gpa > 0.7:\n letter_grades.append('D')\n elif gpa > 0.0:\n letter_grades.append('D-')\n else:\n letter_grades.append('E')\n return letter_grades\n"} +{"task_id": "HumanEval/82", "completion": "def prime_length(string):\n def is_prime(n):\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n \n length = len(string)\n return is_prime(length)\n"} +{"task_id": "HumanEval/83", "completion": "def starts_one_ends(n):\n if n <= 0:\n return 0\n # Numbers starting with 1\n start_with_1 = 10**(n-1) # 1 followed by (n-1) zeros\n # Numbers ending with 1\n end_with_1 = 10**(n-1)\n\n # Counting overlaps (i.e., numbers that both start and end with 1)\n # These are of the form 1...1, and there are (n-2) digits in between\n overlap_count = 10**(n-2) if n > 1 else 1\n\n return start_with_1 + end_with_1 - overlap_count\n "} +{"task_id": "HumanEval/84", "completion": "def solve(N):\n if not (0 <= N <= 10000):\n raise ValueError(\"N must be between 0 and 10000\")\n\n digit_sum = sum(int(digit) for digit in str(N))\n return bin(digit_sum)[2:]\n"} +{"task_id": "HumanEval/85", "completion": "def add(lst):\n total = 0\n for index, value in enumerate(lst):\n if index % 2 != 0 and value % 2 == 0:\n total += value\n return total\n"} +{"task_id": "HumanEval/86", "completion": "def anti_shuffle(s):\n result = []\n for word in s.split(' '):\n sorted_word = ''.join(sorted(word))\n result.append(sorted_word)\n return ' '.join(result)\n"} +{"task_id": "HumanEval/87", "completion": "coordinates = []\n\nfor row_index, row in enumerate(lst):\n for col_index, value in enumerate(row):\n if value == x:\n coordinates.append((row_index, col_index))\n\ncoordinates.sort(key=lambda coord: (coord[0], -coord[1]))\n\nreturn coordinates\n"} +{"task_id": "HumanEval/88", "completion": "def sort_array(array):\n sum_first_last = array[0] + array[-1] if array else 0\n return sorted(array) if sum_first_last % 2 != 0 else sorted(array, reverse=True)\n"} +{"task_id": "HumanEval/89", "completion": "def encrypt(s):\n result = \"\"\n for char in s:\n if 'a' <= char <= 'z': # Check if char is a lowercase letter\n new_char = chr((ord(char) - ord('a') + 4) % 26 + ord('a'))\n result += new_char\n return result\n"} +{"task_id": "HumanEval/90", "completion": "def next_smallest(lst):\n if not lst:\n return None\n unique_elements = list(set(lst))\n unique_elements.sort()\n if len(unique_elements) < 2:\n return None\n return unique_elements[1]\n"} +{"task_id": "HumanEval/91", "completion": "sentences = [s.strip() for s in re.split(r'[.!?]', S) if s] # Split into sentences\nreturn sum(1 for sentence in sentences if sentence.startswith(\"I\")) # Count \"I\"-starting sentences\n"} +{"task_id": "HumanEval/92", "completion": "def any_int(x, y, z):\n return all(isinstance(i, int) for i in (x, y, z)) and (\n x == y + z or y == x + z or z == x + y\n )\n"} +{"task_id": "HumanEval/93", "completion": "def encode(message):\n vowels = {'a': 'c', 'e': 'g', 'i': 'k', 'o': 'q', 'u': 'w',\n 'A': 'C', 'E': 'G', 'I': 'K', 'O': 'Q', 'U': 'W'}\n \n result = []\n for char in message:\n if char in vowels:\n result.append(vowels[char])\n elif char.isalpha():\n result.append(char.swapcase())\n else:\n result.append(char)\n \n return ''.join(result)\n"} +{"task_id": "HumanEval/94", "completion": "def skjkasdkd(lst):\n def is_prime(n):\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n \n largest_prime = None\n \n for num in lst:\n if is_prime(num):\n if largest_prime is None or num > largest_prime:\n largest_prime = num\n \n if largest_prime is None:\n return 0 # or some other default value if there's no prime\n \n return sum(int(digit) for digit in str(largest_prime))\n"} +{"task_id": "HumanEval/95", "completion": "def check_dict_case(d):\n if not d: # Check if the dictionary is empty\n return False\n \n keys = d.keys() # Get all keys from the dictionary\n all_lower = all(isinstance(k, str) and k.islower() for k in keys) # Check if all keys are lower case\n all_upper = all(isinstance(k, str) and k.isupper() for k in keys) # Check if all keys are upper case\n \n return all_lower or all_upper # Return True if either condition is met\n"} +{"task_id": "HumanEval/96", "completion": "def is_prime(num):\n if num < 2:\n return False\n for i in range(2, int(num**0.5) + 1):\n if num % i == 0:\n return False\n return True\n\ndef count_up_to(n):\n return [i for i in range(2, n) if is_prime(i)]\n"} +{"task_id": "HumanEval/97", "completion": "def multiply(a, b):\n # Get the unit digit of each number\n unit_digit_a = abs(a) % 10\n unit_digit_b = abs(b) % 10\n # Return the product of the unit digits\n return unit_digit_a * unit_digit_b\n "} +{"task_id": "HumanEval/98", "completion": "def count_upper(s):\n count = 0\n for i in range(0, len(s), 2):\n if s[i] in 'AEIOU':\n count += 1\n return count\n "} +{"task_id": "HumanEval/99", "completion": "number = float(value)\n floor_value = int(number) # Get the floor value of the number\n ceil_value = floor_value + 1 # Get the ceiling value\n \n if number - floor_value < 0.5:\n return floor_value\n elif number - floor_value > 0.5:\n return ceil_value\n else: # number - floor_value == 0.5\n return ceil_value if number > 0 else floor_value\n"} +{"task_id": "HumanEval/100", "completion": "def make_a_pile(n):\n stones = []\n current_stones = n\n \n for i in range(n):\n stones.append(current_stones)\n if current_stones % 2 == 0: # current_stones is even\n current_stones += 2 # next level will have the next even number\n else:\n current_stones += 2 # next level will have the next odd number\n \n return stones\n"} +{"task_id": "HumanEval/101", "completion": "import re\n\ndef words_string(s):\n return re.split(r'[ ,]+', s)\n"} +{"task_id": "HumanEval/102", "completion": "def choose_num(x, y):\n lower = min(x, y)\n upper = max(x, y)\n \n for num in range(upper, lower - 1, -1):\n if num % 2 == 0:\n return num\n return -1\n"} +{"task_id": "HumanEval/103", "completion": "def rounded_avg(n, m):\n if n > m:\n return -1\n avg = round((n + m) / 2)\n return bin(avg)\n"} +{"task_id": "HumanEval/104", "completion": "result = []\nfor num in x:\n if all(int(digit) % 2 != 0 for digit in str(num)): # Check if all digits are odd\n result.append(num)\nreturn sorted(result)\n"} +{"task_id": "HumanEval/105", "completion": "def by_length(arr):\n filtered = [x for x in arr if 1 <= x <= 9] # Step 1: Filter numbers\n sorted_arr = sorted(filtered) # Step 2: Sort the array\n reversed_arr = sorted_arr[::-1] # Step 3: Reverse the array\n\n # Step 4: Map integers to their names\n number_names = [\"One\", \"Two\", \"Three\", \"Four\", \"Five\", \"Six\", \"Seven\", \"Eight\", \"Nine\"]\n result = [number_names[x - 1] for x in reversed_arr] # Step 5: Replace with names\n return result\n"} +{"task_id": "HumanEval/106", "completion": "result = []\nfor i in range(1, n + 1):\n if i % 2 == 0: # i is even\n factorial = 1\n for j in range(1, i + 1):\n factorial *= j\n result.append(factorial)\n else: # i is odd\n sum_odd = sum(range(1, i + 1))\n result.append(sum_odd)\nreturn result\n"} +{"task_id": "HumanEval/107", "completion": "def even_odd_palindrome(n):\n def is_palindrome(num):\n return str(num) == str(num)[::-1]\n \n odd_count = 0\n even_count = 0\n \n for i in range(1, n + 1):\n if is_palindrome(i):\n if i % 2 == 0:\n even_count += 1\n else:\n odd_count += 1\n \n return (even_count, odd_count)\n"} +{"task_id": "HumanEval/108", "completion": "def count_nums(arr):\n count = 0\n for num in arr:\n digit_sum = sum(int(digit) if num >= 0 else -int(digit) for digit in str(abs(num)))\n if digit_sum > 0:\n count += 1\n return count\n"} +{"task_id": "HumanEval/109", "completion": "def move_one_ball(arr):\n if not arr:\n return True\n\n descents = 0\n n = len(arr)\n\n for i in range(n):\n if arr[i] > arr[(i + 1) % n]: # Use modulo to wrap around\n descents += 1\n\n return descents <= 1\n"} +{"task_id": "HumanEval/110", "completion": "def exchange(lst1, lst2):\n odd_count = sum(1 for x in lst1 if x % 2 != 0)\n even_count_in_lst2 = sum(1 for x in lst2 if x % 2 == 0)\n if odd_count <= even_count_in_lst2:\n return \"YES\"\n else:\n return \"NO\"\n"} +{"task_id": "HumanEval/111", "completion": "def histogram(test):\n counts = {}\n \n # Split the input string into letters and count occurrences\n for letter in test.split():\n counts[letter] = counts.get(letter, 0) + 1\n \n if not counts:\n return {}\n \n # Find the maximum count\n max_count = max(counts.values())\n \n # Gather all letters with the maximum count\n result = {letter: count for letter, count in counts.items() if count == max_count}\n \n return result\n"} +{"task_id": "HumanEval/112", "completion": "def reverse_delete(s, c):\n result = ''.join(char for char in s if char not in c) # Step 1: Remove characters\n is_palindrome = result == result[::-1] # Step 2: Check for palindrome\n return result, is_palindrome # Step 3: Return result\n"} +{"task_id": "HumanEval/113", "completion": "def odd_count(lst):\n result = []\n for s in lst:\n odd_count = sum(1 for char in s if char in '13579')\n result.append(f\"the number of odd elements {odd_count}n the str{odd_count}ng {odd_count} of the {odd_count}nput.\")\n return result\n"} +{"task_id": "HumanEval/114", "completion": "def minSubArraySum(nums):\n min_sum = float('inf')\n current_sum = 0\n\n for num in nums:\n current_sum += num\n if current_sum < min_sum:\n min_sum = current_sum\n if current_sum > 0:\n current_sum = 0\n\n return min_sum\n"} +{"task_id": "HumanEval/115", "completion": "def max_fill(grid, capacity):\n total_water = 0\n \n # Count total water in the grid\n for row in grid:\n total_water += sum(row)\n \n # Calculate number of times to lower buckets\n return math.ceil(total_water / capacity)\n"} +{"task_id": "HumanEval/116", "completion": "def sort_array(arr):\n arr.sort(key=lambda x: (bin(x).count('1'), x))\n return arr\n"} +{"task_id": "HumanEval/117", "completion": "def select_words(s, n):\n if not s:\n return []\n \n def count_consonants(word):\n consonants = \"bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ\"\n return sum(1 for char in word if char in consonants)\n \n words = s.split()\n result = [word for word in words if count_consonants(word) == n]\n \n return result\n"} +{"task_id": "HumanEval/118", "completion": "def get_closest_vowel(word):\n vowels = 'aeiouAEIOU'\n last_consonants = []\n \n # Traverse the string from right to left\n for char in reversed(word):\n if char in vowels:\n # Check for vowels between two consonants\n if len(last_consonants) == 2:\n return char\n elif char.isalpha(): # It is a consonant\n last_consonants.append(char)\n # Keep only the last two consonants\n if len(last_consonants) > 2:\n last_consonants.pop(0)\n\n return \"\"\n"} +{"task_id": "HumanEval/119", "completion": "def match_parens(lst):\n s1, s2 = lst\n\n def is_balanced(s1, s2):\n count = 0\n for char in s1 + s2:\n if char == '(':\n count += 1\n else:\n count -= 1\n if count < 0:\n return False\n return count == 0\n\n return 'Yes' if is_balanced(s1, s2) or is_balanced(s2, s1) else 'No'\n"} +{"task_id": "HumanEval/120", "completion": "def maximum(arr, k):\n return sorted(sorted(arr)[-k:])\n"} +{"task_id": "HumanEval/121", "completion": "total_sum = sum(lst[i] for i in range(len(lst)) if i % 2 == 0 and lst[i] % 2 != 0)\nreturn total_sum\n"} +{"task_id": "HumanEval/122", "completion": "def add_elements(arr, k):\n return sum(x for x in arr[:k] if -10 < x < 100)\n "} +{"task_id": "HumanEval/123", "completion": "def get_odd_collatz(n):\n odd_numbers = []\n \n while n != 1:\n if n % 2 != 0: # n is odd\n odd_numbers.append(n)\n n = n // 2 if n % 2 == 0 else 3 * n + 1\n \n odd_numbers.append(1) # Append 1 as it's also considered odd\n return sorted(odd_numbers)\n"} +{"task_id": "HumanEval/124", "completion": "def valid_date(date):\n if not date:\n return False\n \n if date.count('-') != 2:\n return False\n \n month, day, year = date.split('-')\n \n try:\n month = int(month)\n day = int(day)\n year = int(year)\n except ValueError:\n return False\n \n if month < 1 or month > 12:\n return False\n \n if month in [1, 3, 5, 7, 8, 10, 12]:\n if day < 1 or day > 31:\n return False\n elif month in [4, 6, 9, 11]:\n if day < 1 or day > 30:\n return False\n elif month == 2:\n if day < 1 or day > 29:\n return False\n \n return True\n"} +{"task_id": "HumanEval/125", "completion": "def split_words(txt):\n if any(char.isspace() for char in txt):\n return txt.split()\n elif ',' in txt:\n return txt.split(',')\n else:\n return sum(1 for char in txt if char.islower() and (ord(char) - ord('a')) % 2 == 0)\n"} +{"task_id": "HumanEval/126", "completion": "def is_sorted(lst):\n return lst == sorted(lst) and len(lst) == len(set(lst))\n"} +{"task_id": "HumanEval/127", "completion": "def intersection(interval1, interval2):\n start1, end1 = interval1\n start2, end2 = interval2\n\n # Calculate the intersection\n start_intersection = max(start1, start2)\n end_intersection = min(end1, end2)\n\n # Check if there is an intersection\n if start_intersection >= end_intersection:\n return \"NO\"\n\n # Calculate length of the intersection\n length = end_intersection - start_intersection\n\n # Function to check if a number is prime\n def is_prime(n):\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n\n # Check if the length of the intersection is prime\n if is_prime(length):\n return \"YES\"\n else:\n return \"NO\"\n"} +{"task_id": "HumanEval/128", "completion": "def prod_signs(arr):\n if not arr:\n return None\n \n product_of_signs = 1\n sum_of_magnitudes = 0\n \n for num in arr:\n if num > 0:\n sum_of_magnitudes += num\n elif num < 0:\n sum_of_magnitudes += -num\n product_of_signs *= -1\n else: # num == 0\n product_of_signs = 0\n \n return sum_of_magnitudes * product_of_signs\n"} +{"task_id": "HumanEval/129", "completion": "def minPath(grid, k):\n from itertools import product\n \n n = len(grid)\n best_path = []\n\n def dfs(r, c, path):\n nonlocal best_path\n \n if len(path) == k:\n if not best_path or path < best_path:\n best_path = path[:]\n return\n \n directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]\n for dr, dc in directions:\n nr, nc = r + dr, c + dc\n if 0 <= nr < n and 0 <= nc < n:\n path.append(grid[nr][nc])\n dfs(nr, nc, path)\n path.pop()\n\n for i, j in product(range(n), repeat=2):\n dfs(i, j, [grid[i][j]])\n\n return best_path\n"} +{"task_id": "HumanEval/130", "completion": "def tri(n):\n tribonacci = []\n \n for i in range(n + 1):\n if i == 0:\n tribonacci.append(1)\n elif i == 1:\n tribonacci.append(3)\n elif i % 2 == 0: # Even\n tribonacci.append(1 + i / 2)\n else: # Odd\n tribonacci.append(\n tribonacci[i - 1] + tribonacci[i - 2] + tribonacci[i + 1] if (i + 1 <= n) else tribonacci[i - 1] + tribonacci[i - 2]\n )\n \n return tribonacci\n"} +{"task_id": "HumanEval/131", "completion": "def digits(n):\n product = 1\n has_odd = False\n while n > 0:\n digit = n % 10\n if digit % 2 != 0: # Check if the digit is odd\n product *= digit\n has_odd = True\n n //= 10 # Remove the last digit\n return product if has_odd else 0\n "} +{"task_id": "HumanEval/132", "completion": "def is_nested(string):\n stack = []\n nested = False\n\n for char in string:\n if char == '[':\n stack.append(char)\n elif char == ']':\n if stack:\n top = stack.pop()\n if stack: # Check if there are still brackets in the stack\n nested = True # We found a nested bracket\n else:\n return False # More closing brackets than opening\n\n # If there are still items in stack, that means we have unmatched opening brackets\n return nested\n\n# Example tests\nprint(is_nested('[[]]')) # \u279e True\nprint(is_nested('[]]]]]]][[[[[]')) # \u279e False\nprint(is_nested('[][]')) # \u279e False\nprint(is_nested('[]')) # \u279e False\nprint(is_nested('[[][]]')) # \u279e True\nprint(is_nested('[[]][[')) # \u279e True\n"} +{"task_id": "HumanEval/133", "completion": "import math\n\ndef sum_squares(lst):\n return sum(math.ceil(x) ** 2 for x in lst)\n"} +{"task_id": "HumanEval/134", "completion": "def check_if_last_char_is_a_letter(txt):\n txt = txt.rstrip() # Remove trailing spaces\n if len(txt) == 0: # Check if the string is empty\n return False\n last_char = txt[-1] # Get the last character\n\n # Check if last_char is a letter and is not part of a word\n return last_char.isalpha() and (len(txt) == 1 or txt[-2] == ' ')\n"} +{"task_id": "HumanEval/135", "completion": "for i in range(1, len(arr)):\n if arr[i] < arr[i - 1]:\n return i\n return -1\n"} +{"task_id": "HumanEval/136", "completion": "largest_smallest_integers(lst):\n largest_negative = None\n smallest_positive = None\n \n for number in lst:\n if number < 0:\n if largest_negative is None or number > largest_negative:\n largest_negative = number\n elif number > 0:\n if smallest_positive is None or number < smallest_positive:\n smallest_positive = number\n\n return (largest_negative, smallest_positive)\n"} +{"task_id": "HumanEval/137", "completion": "def compare_one(a, b):\n def to_float(value):\n if isinstance(value, str):\n value = value.replace(',', '.') \n return float(value)\n\n try:\n float_a = to_float(a)\n float_b = to_float(b)\n except ValueError:\n return None\n\n if float_a > float_b:\n return a\n elif float_a < float_b:\n return b\n else:\n return None\n"} +{"task_id": "HumanEval/138", "completion": "def is_equal_to_sum_even(n):\n return n >= 8 and n % 2 == 0\n"} +{"task_id": "HumanEval/139", "completion": "def special_factorial(n):\n def factorial(x):\n if x == 0 or x == 1:\n return 1\n else:\n result = 1\n for i in range(2, x + 1):\n result *= i\n return result\n\n result = 1\n for i in range(1, n + 1):\n result *= factorial(i)\n \n return result\n"} +{"task_id": "HumanEval/140", "completion": "def fix_spaces(text):\n import re\n text = text.lstrip(' ')\n text = re.sub(r' {2,}', '-', text)\n text = text.replace(' ', '_')\n if text.startswith('_'):\n text = '_' + text.strip('_')\n return text\n"} +{"task_id": "HumanEval/141", "completion": "def file_name_check(file_name):\n # Check for one dot\n if file_name.count('.') != 1:\n return 'No'\n \n # Split the name into the part before and after the dot\n name_part, ext_part = file_name.split('.')\n \n # Check if the name part is empty and starts with a letter\n if not name_part or not name_part[0].isalpha():\n return 'No'\n \n # Check for valid file extensions\n valid_extensions = ['txt', 'exe', 'dll']\n if ext_part not in valid_extensions:\n return 'No'\n \n # Count the digits in the file name\n digit_count = sum(c.isdigit() for c in file_name)\n if digit_count > 3:\n return 'No'\n \n return 'Yes'\n"} +{"task_id": "HumanEval/142", "completion": "def sum_squares(lst):\n total_sum = 0\n for index, value in enumerate(lst):\n if index % 3 == 0:\n total_sum += value ** 2\n elif index % 4 == 0:\n total_sum += value ** 3\n else:\n total_sum += value\n return total_sum\n"} +{"task_id": "HumanEval/143", "completion": "def words_in_sentence(sentence):\n def is_prime(n):\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n\n words = sentence.split()\n prime_length_words = [word for word in words if is_prime(len(word))]\n return ' '.join(prime_length_words)\n"} +{"task_id": "HumanEval/144", "completion": "def simplify(x, n):\n num1, denom1 = map(int, x.split('/'))\n num2, denom2 = map(int, n.split('/'))\n \n result_numerator = num1 * num2\n result_denominator = denom1 * denom2\n \n return result_numerator % result_denominator == 0\n"} +{"task_id": "HumanEval/145", "completion": "def order_by_points(nums):\n def sum_of_digits(n):\n return sum(int(digit) for digit in str(abs(n)))\n\n return sorted(nums, key=lambda x: (sum_of_digits(x), nums.index(x)))\n"} +{"task_id": "HumanEval/146", "completion": "def specialFilter(nums):\n count = 0\n for num in nums:\n if num > 10:\n num_str = str(num)\n first_digit = int(num_str[0])\n last_digit = int(num_str[-1])\n if first_digit % 2 != 0 and last_digit % 2 != 0:\n count += 1\n return count\n"} +{"task_id": "HumanEval/147", "completion": "a = [i * i - i + 1 for i in range(1, n + 1)]\ncount = 0\n\n# Iterate through all possible triples\nfor i in range(n):\n for j in range(i + 1, n):\n for k in range(j + 1, n):\n if (a[i] + a[j] + a[k]) % 3 == 0:\n count += 1\n \nreturn count\n"} +{"task_id": "HumanEval/148", "completion": "def bf(planet1, planet2):\n planets = [\"Mercury\", \"Venus\", \"Earth\", \"Mars\", \"Jupiter\", \"Saturn\", \"Uranus\", \"Neptune\"]\n if planet1 not in planets or planet2 not in planets:\n return ()\n \n index1 = planets.index(planet1)\n index2 = planets.index(planet2)\n \n if index1 > index2:\n index1, index2 = index2, index1\n \n return tuple(planets[index1 + 1:index2])\n"} +{"task_id": "HumanEval/149", "completion": "def sorted_list_sum(lst):\n # Remove strings with odd lengths\n filtered = [s for s in lst if len(s) % 2 == 0]\n # Sort by length and then alphabetically\n sorted_list = sorted(filtered, key=lambda x: (len(x), x))\n return sorted_list\n"} +{"task_id": "HumanEval/150", "completion": "def x_or_y(n, x, y):\n def is_prime(num):\n if num <= 1:\n return False\n for i in range(2, int(num**0.5) + 1):\n if num % i == 0:\n return False\n return True\n \n return x if is_prime(n) else y\n"} +{"task_id": "HumanEval/151", "completion": "def double_the_difference(lst):\n odd_squares_sum = sum(x ** 2 for x in lst if x >= 0 and x % 2 == 1)\n return odd_squares_sum\n"} +{"task_id": "HumanEval/152", "completion": "def compare(game, guess):\n return [abs(g - s) for g, s in zip(guess, game)]\n"} +{"task_id": "HumanEval/153", "completion": "def Strongest_Extension(class_name, extensions):\n strongest_extension = \"\"\n max_strength = float('-inf') # Initialize to negative infinity to find the max\n\n for extension in extensions:\n CAP = sum(1 for char in extension if char.isupper())\n SM = sum(1 for char in extension if char.islower())\n strength = CAP - SM\n \n if strength > max_strength: # Update if this extension is stronger\n max_strength = strength\n strongest_extension = extension\n\n return f\"{class_name}.{strongest_extension}\"\n"} +{"task_id": "HumanEval/154", "completion": "def cycpattern_check(a, b):\n if len(b) == 0:\n return True\n return any(b[i:i+len(b)] in a for i in range(len(b)))\n"} +{"task_id": "HumanEval/155", "completion": "even_count = 0\n odd_count = 0\n\n for digit in str(abs(num)):\n if int(digit) % 2 == 0:\n even_count += 1\n else:\n odd_count += 1\n\n return (even_count, odd_count)\n"} +{"task_id": "HumanEval/156", "completion": "def int_to_mini_roman(number):\n roman_numerals = [\n (1000, 'm'), (900, 'cm'), (500, 'd'), (400, 'cd'),\n (100, 'c'), (90, 'xc'), (50, 'l'), (40, 'xl'),\n (10, 'x'), (9, 'ix'), (5, 'v'), (4, 'iv'), (1, 'i')\n ]\n \n result = \"\"\n \n for value, numeral in roman_numerals:\n while number >= value:\n result += numeral\n number -= value\n \n return result\n"} +{"task_id": "HumanEval/157", "completion": "sides = sorted([a, b, c])\nreturn sides[0]**2 + sides[1]**2 == sides[2]**2\n"} +{"task_id": "HumanEval/158", "completion": "def find_max(words):\n max_word = \"\"\n max_unique_count = 0\n \n for word in words:\n unique_chars = len(set(word))\n \n if (unique_chars > max_unique_count or \n (unique_chars == max_unique_count and word < max_word)):\n max_word = word\n max_unique_count = unique_chars\n \n return max_word\n"} +{"task_id": "HumanEval/159", "completion": "def eat(number, need, remaining):\n total_eaten = number\n if need <= remaining:\n total_eaten += need\n remaining -= need\n else:\n total_eaten += remaining\n remaining = 0\n return [total_eaten, remaining]\n"} +{"task_id": "HumanEval/160", "completion": "def do_algebra(operator, operand):\n result = operand[0]\n for i in range(len(operator)):\n if operator[i] == '+':\n result += operand[i + 1]\n elif operator[i] == '-':\n result -= operand[i + 1]\n elif operator[i] == '*':\n result *= operand[i + 1]\n elif operator[i] == '//':\n result //= operand[i + 1]\n elif operator[i] == '**':\n result **= operand[i + 1]\n return result\n"} +{"task_id": "HumanEval/161", "completion": "def solve(s):\n # Check if there are any letters in the input string\n has_letter = any(c.isalpha() for c in s)\n\n if not has_letter:\n # Reverse the string if no letters are present\n return s[::-1]\n else:\n # Create a list to hold the new characters\n result = []\n # Iterate through each character in the string\n for c in s:\n if c.isalpha():\n # Reverse case for letters\n if c.islower():\n result.append(c.upper())\n else:\n result.append(c.lower())\n else:\n # Keep non-letter characters as they are\n result.append(c)\n return ''.join(result)\n "} +{"task_id": "HumanEval/162", "completion": "import hashlib\n\ndef string_to_md5(text):\n if text == \"\":\n return None\n hash_object = hashlib.md5(text.encode())\n return hash_object.hexdigest()\n"} +{"task_id": "HumanEval/163", "completion": "def generate_integers(a, b):\n lower = min(a, b)\n upper = max(a, b)\n return [n for n in range(lower, upper + 1) if n % 2 == 0]\n"} diff --git a/experiment/humaneval/sample.py b/experiment/humaneval/sample.py new file mode 100644 index 000000000..6e9b0a4a1 --- /dev/null +++ b/experiment/humaneval/sample.py @@ -0,0 +1,11 @@ +from human_eval.data import write_jsonl, read_problems + +problems = read_problems() + +num_samples_per_task = 1 +samples = [ + dict(task_id=task_id, completion=problems[task_id]["prompt"]) + for task_id in problems + for _ in range(num_samples_per_task) +] +write_jsonl("samples.jsonl", samples) \ No newline at end of file diff --git a/experiment/humaneval/samples.jsonl b/experiment/humaneval/samples.jsonl new file mode 100644 index 000000000..4cfc786db --- /dev/null +++ b/experiment/humaneval/samples.jsonl @@ -0,0 +1,164 @@ +{"task_id": "HumanEval/0", "completion": "from typing import List\n\n\ndef has_close_elements(numbers: List[float], threshold: float) -> bool:\n \"\"\" Check if in given list of numbers, are any two numbers closer to each other than\n given threshold.\n >>> has_close_elements([1.0, 2.0, 3.0], 0.5)\n False\n >>> has_close_elements([1.0, 2.8, 3.0, 4.0, 5.0, 2.0], 0.3)\n True\n \"\"\"\n"} +{"task_id": "HumanEval/1", "completion": "from typing import List\n\n\ndef separate_paren_groups(paren_string: str) -> List[str]:\n \"\"\" Input to this function is a string containing multiple groups of nested parentheses. Your goal is to\n separate those group into separate strings and return the list of those.\n Separate groups are balanced (each open brace is properly closed) and not nested within each other\n Ignore any spaces in the input string.\n >>> separate_paren_groups('( ) (( )) (( )( ))')\n ['()', '(())', '(()())']\n \"\"\"\n"} +{"task_id": "HumanEval/2", "completion": "\n\ndef truncate_number(number: float) -> float:\n \"\"\" Given a positive floating point number, it can be decomposed into\n and integer part (largest integer smaller than given number) and decimals\n (leftover part always smaller than 1).\n\n Return the decimal part of the number.\n >>> truncate_number(3.5)\n 0.5\n \"\"\"\n"} +{"task_id": "HumanEval/3", "completion": "from typing import List\n\n\ndef below_zero(operations: List[int]) -> bool:\n \"\"\" You're given a list of deposit and withdrawal operations on a bank account that starts with\n zero balance. Your task is to detect if at any point the balance of account fallls below zero, and\n at that point function should return True. Otherwise it should return False.\n >>> below_zero([1, 2, 3])\n False\n >>> below_zero([1, 2, -4, 5])\n True\n \"\"\"\n"} +{"task_id": "HumanEval/4", "completion": "from typing import List\n\n\ndef mean_absolute_deviation(numbers: List[float]) -> float:\n \"\"\" For a given list of input numbers, calculate Mean Absolute Deviation\n around the mean of this dataset.\n Mean Absolute Deviation is the average absolute difference between each\n element and a centerpoint (mean in this case):\n MAD = average | x - x_mean |\n >>> mean_absolute_deviation([1.0, 2.0, 3.0, 4.0])\n 1.0\n \"\"\"\n"} +{"task_id": "HumanEval/5", "completion": "from typing import List\n\n\ndef intersperse(numbers: List[int], delimeter: int) -> List[int]:\n \"\"\" Insert a number 'delimeter' between every two consecutive elements of input list `numbers'\n >>> intersperse([], 4)\n []\n >>> intersperse([1, 2, 3], 4)\n [1, 4, 2, 4, 3]\n \"\"\"\n"} +{"task_id": "HumanEval/6", "completion": "from typing import List\n\n\ndef parse_nested_parens(paren_string: str) -> List[int]:\n \"\"\" Input to this function is a string represented multiple groups for nested parentheses separated by spaces.\n For each of the group, output the deepest level of nesting of parentheses.\n E.g. (()()) has maximum two levels of nesting while ((())) has three.\n\n >>> parse_nested_parens('(()()) ((())) () ((())()())')\n [2, 3, 1, 3]\n \"\"\"\n"} +{"task_id": "HumanEval/7", "completion": "from typing import List\n\n\ndef filter_by_substring(strings: List[str], substring: str) -> List[str]:\n \"\"\" Filter an input list of strings only for ones that contain given substring\n >>> filter_by_substring([], 'a')\n []\n >>> filter_by_substring(['abc', 'bacd', 'cde', 'array'], 'a')\n ['abc', 'bacd', 'array']\n \"\"\"\n"} +{"task_id": "HumanEval/8", "completion": "from typing import List, Tuple\n\n\ndef sum_product(numbers: List[int]) -> Tuple[int, int]:\n \"\"\" For a given list of integers, return a tuple consisting of a sum and a product of all the integers in a list.\n Empty sum should be equal to 0 and empty product should be equal to 1.\n >>> sum_product([])\n (0, 1)\n >>> sum_product([1, 2, 3, 4])\n (10, 24)\n \"\"\"\n"} +{"task_id": "HumanEval/9", "completion": "from typing import List, Tuple\n\n\ndef rolling_max(numbers: List[int]) -> List[int]:\n \"\"\" From a given list of integers, generate a list of rolling maximum element found until given moment\n in the sequence.\n >>> rolling_max([1, 2, 3, 2, 3, 4, 2])\n [1, 2, 3, 3, 3, 4, 4]\n \"\"\"\n"} +{"task_id": "HumanEval/10", "completion": "\n\ndef is_palindrome(string: str) -> bool:\n \"\"\" Test if given string is a palindrome \"\"\"\n return string == string[::-1]\n\n\ndef make_palindrome(string: str) -> str:\n \"\"\" Find the shortest palindrome that begins with a supplied string.\n Algorithm idea is simple:\n - Find the longest postfix of supplied string that is a palindrome.\n - Append to the end of the string reverse of a string prefix that comes before the palindromic suffix.\n >>> make_palindrome('')\n ''\n >>> make_palindrome('cat')\n 'catac'\n >>> make_palindrome('cata')\n 'catac'\n \"\"\"\n"} +{"task_id": "HumanEval/11", "completion": "from typing import List\n\n\ndef string_xor(a: str, b: str) -> str:\n \"\"\" Input are two strings a and b consisting only of 1s and 0s.\n Perform binary XOR on these inputs and return result also as a string.\n >>> string_xor('010', '110')\n '100'\n \"\"\"\n"} +{"task_id": "HumanEval/12", "completion": "from typing import List, Optional\n\n\ndef longest(strings: List[str]) -> Optional[str]:\n \"\"\" Out of list of strings, return the longest one. Return the first one in case of multiple\n strings of the same length. Return None in case the input list is empty.\n >>> longest([])\n\n >>> longest(['a', 'b', 'c'])\n 'a'\n >>> longest(['a', 'bb', 'ccc'])\n 'ccc'\n \"\"\"\n"} +{"task_id": "HumanEval/13", "completion": "\n\ndef greatest_common_divisor(a: int, b: int) -> int:\n \"\"\" Return a greatest common divisor of two integers a and b\n >>> greatest_common_divisor(3, 5)\n 1\n >>> greatest_common_divisor(25, 15)\n 5\n \"\"\"\n"} +{"task_id": "HumanEval/14", "completion": "from typing import List\n\n\ndef all_prefixes(string: str) -> List[str]:\n \"\"\" Return list of all prefixes from shortest to longest of the input string\n >>> all_prefixes('abc')\n ['a', 'ab', 'abc']\n \"\"\"\n"} +{"task_id": "HumanEval/15", "completion": "\n\ndef string_sequence(n: int) -> str:\n \"\"\" Return a string containing space-delimited numbers starting from 0 upto n inclusive.\n >>> string_sequence(0)\n '0'\n >>> string_sequence(5)\n '0 1 2 3 4 5'\n \"\"\"\n"} +{"task_id": "HumanEval/16", "completion": "\n\ndef count_distinct_characters(string: str) -> int:\n \"\"\" Given a string, find out how many distinct characters (regardless of case) does it consist of\n >>> count_distinct_characters('xyzXYZ')\n 3\n >>> count_distinct_characters('Jerry')\n 4\n \"\"\"\n"} +{"task_id": "HumanEval/17", "completion": "from typing import List\n\n\ndef parse_music(music_string: str) -> List[int]:\n \"\"\" Input to this function is a string representing musical notes in a special ASCII format.\n Your task is to parse this string and return list of integers corresponding to how many beats does each\n not last.\n\n Here is a legend:\n 'o' - whole note, lasts four beats\n 'o|' - half note, lasts two beats\n '.|' - quater note, lasts one beat\n\n >>> parse_music('o o| .| o| o| .| .| .| .| o o')\n [4, 2, 1, 2, 2, 1, 1, 1, 1, 4, 4]\n \"\"\"\n"} +{"task_id": "HumanEval/18", "completion": "\n\ndef how_many_times(string: str, substring: str) -> int:\n \"\"\" Find how many times a given substring can be found in the original string. Count overlaping cases.\n >>> how_many_times('', 'a')\n 0\n >>> how_many_times('aaa', 'a')\n 3\n >>> how_many_times('aaaa', 'aa')\n 3\n \"\"\"\n"} +{"task_id": "HumanEval/19", "completion": "from typing import List\n\n\ndef sort_numbers(numbers: str) -> str:\n \"\"\" Input is a space-delimited string of numberals from 'zero' to 'nine'.\n Valid choices are 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight' and 'nine'.\n Return the string with numbers sorted from smallest to largest\n >>> sort_numbers('three one five')\n 'one three five'\n \"\"\"\n"} +{"task_id": "HumanEval/20", "completion": "from typing import List, Tuple\n\n\ndef find_closest_elements(numbers: List[float]) -> Tuple[float, float]:\n \"\"\" From a supplied list of numbers (of length at least two) select and return two that are the closest to each\n other and return them in order (smaller number, larger number).\n >>> find_closest_elements([1.0, 2.0, 3.0, 4.0, 5.0, 2.2])\n (2.0, 2.2)\n >>> find_closest_elements([1.0, 2.0, 3.0, 4.0, 5.0, 2.0])\n (2.0, 2.0)\n \"\"\"\n"} +{"task_id": "HumanEval/21", "completion": "from typing import List\n\n\ndef rescale_to_unit(numbers: List[float]) -> List[float]:\n \"\"\" Given list of numbers (of at least two elements), apply a linear transform to that list,\n such that the smallest number will become 0 and the largest will become 1\n >>> rescale_to_unit([1.0, 2.0, 3.0, 4.0, 5.0])\n [0.0, 0.25, 0.5, 0.75, 1.0]\n \"\"\"\n"} +{"task_id": "HumanEval/22", "completion": "from typing import List, Any\n\n\ndef filter_integers(values: List[Any]) -> List[int]:\n \"\"\" Filter given list of any python values only for integers\n >>> filter_integers(['a', 3.14, 5])\n [5]\n >>> filter_integers([1, 2, 3, 'abc', {}, []])\n [1, 2, 3]\n \"\"\"\n"} +{"task_id": "HumanEval/23", "completion": "\n\ndef strlen(string: str) -> int:\n \"\"\" Return length of given string\n >>> strlen('')\n 0\n >>> strlen('abc')\n 3\n \"\"\"\n"} +{"task_id": "HumanEval/24", "completion": "\n\ndef largest_divisor(n: int) -> int:\n \"\"\" For a given number n, find the largest number that divides n evenly, smaller than n\n >>> largest_divisor(15)\n 5\n \"\"\"\n"} +{"task_id": "HumanEval/25", "completion": "from typing import List\n\n\ndef factorize(n: int) -> List[int]:\n \"\"\" Return list of prime factors of given integer in the order from smallest to largest.\n Each of the factors should be listed number of times corresponding to how many times it appeares in factorization.\n Input number should be equal to the product of all factors\n >>> factorize(8)\n [2, 2, 2]\n >>> factorize(25)\n [5, 5]\n >>> factorize(70)\n [2, 5, 7]\n \"\"\"\n"} +{"task_id": "HumanEval/26", "completion": "from typing import List\n\n\ndef remove_duplicates(numbers: List[int]) -> List[int]:\n \"\"\" From a list of integers, remove all elements that occur more than once.\n Keep order of elements left the same as in the input.\n >>> remove_duplicates([1, 2, 3, 2, 4])\n [1, 3, 4]\n \"\"\"\n"} +{"task_id": "HumanEval/27", "completion": "\n\ndef flip_case(string: str) -> str:\n \"\"\" For a given string, flip lowercase characters to uppercase and uppercase to lowercase.\n >>> flip_case('Hello')\n 'hELLO'\n \"\"\"\n"} +{"task_id": "HumanEval/28", "completion": "from typing import List\n\n\ndef concatenate(strings: List[str]) -> str:\n \"\"\" Concatenate list of strings into a single string\n >>> concatenate([])\n ''\n >>> concatenate(['a', 'b', 'c'])\n 'abc'\n \"\"\"\n"} +{"task_id": "HumanEval/29", "completion": "from typing import List\n\n\ndef filter_by_prefix(strings: List[str], prefix: str) -> List[str]:\n \"\"\" Filter an input list of strings only for ones that start with a given prefix.\n >>> filter_by_prefix([], 'a')\n []\n >>> filter_by_prefix(['abc', 'bcd', 'cde', 'array'], 'a')\n ['abc', 'array']\n \"\"\"\n"} +{"task_id": "HumanEval/30", "completion": "\n\ndef get_positive(l: list):\n \"\"\"Return only positive numbers in the list.\n >>> get_positive([-1, 2, -4, 5, 6])\n [2, 5, 6]\n >>> get_positive([5, 3, -5, 2, -3, 3, 9, 0, 123, 1, -10])\n [5, 3, 2, 3, 9, 123, 1]\n \"\"\"\n"} +{"task_id": "HumanEval/31", "completion": "\n\ndef is_prime(n):\n \"\"\"Return true if a given number is prime, and false otherwise.\n >>> is_prime(6)\n False\n >>> is_prime(101)\n True\n >>> is_prime(11)\n True\n >>> is_prime(13441)\n True\n >>> is_prime(61)\n True\n >>> is_prime(4)\n False\n >>> is_prime(1)\n False\n \"\"\"\n"} +{"task_id": "HumanEval/32", "completion": "import math\n\n\ndef poly(xs: list, x: float):\n \"\"\"\n Evaluates polynomial with coefficients xs at point x.\n return xs[0] + xs[1] * x + xs[1] * x^2 + .... xs[n] * x^n\n \"\"\"\n return sum([coeff * math.pow(x, i) for i, coeff in enumerate(xs)])\n\n\ndef find_zero(xs: list):\n \"\"\" xs are coefficients of a polynomial.\n find_zero find x such that poly(x) = 0.\n find_zero returns only only zero point, even if there are many.\n Moreover, find_zero only takes list xs having even number of coefficients\n and largest non zero coefficient as it guarantees\n a solution.\n >>> round(find_zero([1, 2]), 2) # f(x) = 1 + 2x\n -0.5\n >>> round(find_zero([-6, 11, -6, 1]), 2) # (x - 1) * (x - 2) * (x - 3) = -6 + 11x - 6x^2 + x^3\n 1.0\n \"\"\"\n"} +{"task_id": "HumanEval/33", "completion": "\n\ndef sort_third(l: list):\n \"\"\"This function takes a list l and returns a list l' such that\n l' is identical to l in the indicies that are not divisible by three, while its values at the indicies that are divisible by three are equal\n to the values of the corresponding indicies of l, but sorted.\n >>> sort_third([1, 2, 3])\n [1, 2, 3]\n >>> sort_third([5, 6, 3, 4, 8, 9, 2])\n [2, 6, 3, 4, 8, 9, 5]\n \"\"\"\n"} +{"task_id": "HumanEval/34", "completion": "\n\ndef unique(l: list):\n \"\"\"Return sorted unique elements in a list\n >>> unique([5, 3, 5, 2, 3, 3, 9, 0, 123])\n [0, 2, 3, 5, 9, 123]\n \"\"\"\n"} +{"task_id": "HumanEval/35", "completion": "\n\ndef max_element(l: list):\n \"\"\"Return maximum element in the list.\n >>> max_element([1, 2, 3])\n 3\n >>> max_element([5, 3, -5, 2, -3, 3, 9, 0, 123, 1, -10])\n 123\n \"\"\"\n"} +{"task_id": "HumanEval/36", "completion": "\n\ndef fizz_buzz(n: int):\n \"\"\"Return the number of times the digit 7 appears in integers less than n which are divisible by 11 or 13.\n >>> fizz_buzz(50)\n 0\n >>> fizz_buzz(78)\n 2\n >>> fizz_buzz(79)\n 3\n \"\"\"\n"} +{"task_id": "HumanEval/37", "completion": "\n\ndef sort_even(l: list):\n \"\"\"This function takes a list l and returns a list l' such that\n l' is identical to l in the odd indicies, while its values at the even indicies are equal\n to the values of the even indicies of l, but sorted.\n >>> sort_even([1, 2, 3])\n [1, 2, 3]\n >>> sort_even([5, 6, 3, 4])\n [3, 6, 5, 4]\n \"\"\"\n"} +{"task_id": "HumanEval/38", "completion": "\n\ndef encode_cyclic(s: str):\n \"\"\"\n returns encoded string by cycling groups of three characters.\n \"\"\"\n # split string to groups. Each of length 3.\n groups = [s[(3 * i):min((3 * i + 3), len(s))] for i in range((len(s) + 2) // 3)]\n # cycle elements in each group. Unless group has fewer elements than 3.\n groups = [(group[1:] + group[0]) if len(group) == 3 else group for group in groups]\n return \"\".join(groups)\n\n\ndef decode_cyclic(s: str):\n \"\"\"\n takes as input string encoded with encode_cyclic function. Returns decoded string.\n \"\"\"\n"} +{"task_id": "HumanEval/39", "completion": "\n\ndef prime_fib(n: int):\n \"\"\"\n prime_fib returns n-th number that is a Fibonacci number and it's also prime.\n >>> prime_fib(1)\n 2\n >>> prime_fib(2)\n 3\n >>> prime_fib(3)\n 5\n >>> prime_fib(4)\n 13\n >>> prime_fib(5)\n 89\n \"\"\"\n"} +{"task_id": "HumanEval/40", "completion": "\n\ndef triples_sum_to_zero(l: list):\n \"\"\"\n triples_sum_to_zero takes a list of integers as an input.\n it returns True if there are three distinct elements in the list that\n sum to zero, and False otherwise.\n\n >>> triples_sum_to_zero([1, 3, 5, 0])\n False\n >>> triples_sum_to_zero([1, 3, -2, 1])\n True\n >>> triples_sum_to_zero([1, 2, 3, 7])\n False\n >>> triples_sum_to_zero([2, 4, -5, 3, 9, 7])\n True\n >>> triples_sum_to_zero([1])\n False\n \"\"\"\n"} +{"task_id": "HumanEval/41", "completion": "\n\ndef car_race_collision(n: int):\n \"\"\"\n Imagine a road that's a perfectly straight infinitely long line.\n n cars are driving left to right; simultaneously, a different set of n cars\n are driving right to left. The two sets of cars start out being very far from\n each other. All cars move in the same speed. Two cars are said to collide\n when a car that's moving left to right hits a car that's moving right to left.\n However, the cars are infinitely sturdy and strong; as a result, they continue moving\n in their trajectory as if they did not collide.\n\n This function outputs the number of such collisions.\n \"\"\"\n"} +{"task_id": "HumanEval/42", "completion": "\n\ndef incr_list(l: list):\n \"\"\"Return list with elements incremented by 1.\n >>> incr_list([1, 2, 3])\n [2, 3, 4]\n >>> incr_list([5, 3, 5, 2, 3, 3, 9, 0, 123])\n [6, 4, 6, 3, 4, 4, 10, 1, 124]\n \"\"\"\n"} +{"task_id": "HumanEval/43", "completion": "\n\ndef pairs_sum_to_zero(l):\n \"\"\"\n pairs_sum_to_zero takes a list of integers as an input.\n it returns True if there are two distinct elements in the list that\n sum to zero, and False otherwise.\n >>> pairs_sum_to_zero([1, 3, 5, 0])\n False\n >>> pairs_sum_to_zero([1, 3, -2, 1])\n False\n >>> pairs_sum_to_zero([1, 2, 3, 7])\n False\n >>> pairs_sum_to_zero([2, 4, -5, 3, 5, 7])\n True\n >>> pairs_sum_to_zero([1])\n False\n \"\"\"\n"} +{"task_id": "HumanEval/44", "completion": "\n\ndef change_base(x: int, base: int):\n \"\"\"Change numerical base of input number x to base.\n return string representation after the conversion.\n base numbers are less than 10.\n >>> change_base(8, 3)\n '22'\n >>> change_base(8, 2)\n '1000'\n >>> change_base(7, 2)\n '111'\n \"\"\"\n"} +{"task_id": "HumanEval/45", "completion": "\n\ndef triangle_area(a, h):\n \"\"\"Given length of a side and high return area for a triangle.\n >>> triangle_area(5, 3)\n 7.5\n \"\"\"\n"} +{"task_id": "HumanEval/46", "completion": "\n\ndef fib4(n: int):\n \"\"\"The Fib4 number sequence is a sequence similar to the Fibbonacci sequnece that's defined as follows:\n fib4(0) -> 0\n fib4(1) -> 0\n fib4(2) -> 2\n fib4(3) -> 0\n fib4(n) -> fib4(n-1) + fib4(n-2) + fib4(n-3) + fib4(n-4).\n Please write a function to efficiently compute the n-th element of the fib4 number sequence. Do not use recursion.\n >>> fib4(5)\n 4\n >>> fib4(6)\n 8\n >>> fib4(7)\n 14\n \"\"\"\n"} +{"task_id": "HumanEval/47", "completion": "\n\ndef median(l: list):\n \"\"\"Return median of elements in the list l.\n >>> median([3, 1, 2, 4, 5])\n 3\n >>> median([-10, 4, 6, 1000, 10, 20])\n 15.0\n \"\"\"\n"} +{"task_id": "HumanEval/48", "completion": "\n\ndef is_palindrome(text: str):\n \"\"\"\n Checks if given string is a palindrome\n >>> is_palindrome('')\n True\n >>> is_palindrome('aba')\n True\n >>> is_palindrome('aaaaa')\n True\n >>> is_palindrome('zbcd')\n False\n \"\"\"\n"} +{"task_id": "HumanEval/49", "completion": "\n\ndef modp(n: int, p: int):\n \"\"\"Return 2^n modulo p (be aware of numerics).\n >>> modp(3, 5)\n 3\n >>> modp(1101, 101)\n 2\n >>> modp(0, 101)\n 1\n >>> modp(3, 11)\n 8\n >>> modp(100, 101)\n 1\n \"\"\"\n"} +{"task_id": "HumanEval/50", "completion": "\n\ndef encode_shift(s: str):\n \"\"\"\n returns encoded string by shifting every character by 5 in the alphabet.\n \"\"\"\n return \"\".join([chr(((ord(ch) + 5 - ord(\"a\")) % 26) + ord(\"a\")) for ch in s])\n\n\ndef decode_shift(s: str):\n \"\"\"\n takes as input string encoded with encode_shift function. Returns decoded string.\n \"\"\"\n"} +{"task_id": "HumanEval/51", "completion": "\n\ndef remove_vowels(text):\n \"\"\"\n remove_vowels is a function that takes string and returns string without vowels.\n >>> remove_vowels('')\n ''\n >>> remove_vowels(\"abcdef\\nghijklm\")\n 'bcdf\\nghjklm'\n >>> remove_vowels('abcdef')\n 'bcdf'\n >>> remove_vowels('aaaaa')\n ''\n >>> remove_vowels('aaBAA')\n 'B'\n >>> remove_vowels('zbcd')\n 'zbcd'\n \"\"\"\n"} +{"task_id": "HumanEval/52", "completion": "\n\ndef below_threshold(l: list, t: int):\n \"\"\"Return True if all numbers in the list l are below threshold t.\n >>> below_threshold([1, 2, 4, 10], 100)\n True\n >>> below_threshold([1, 20, 4, 10], 5)\n False\n \"\"\"\n"} +{"task_id": "HumanEval/53", "completion": "\n\ndef add(x: int, y: int):\n \"\"\"Add two numbers x and y\n >>> add(2, 3)\n 5\n >>> add(5, 7)\n 12\n \"\"\"\n"} +{"task_id": "HumanEval/54", "completion": "\n\ndef same_chars(s0: str, s1: str):\n \"\"\"\n Check if two words have the same characters.\n >>> same_chars('eabcdzzzz', 'dddzzzzzzzddeddabc')\n True\n >>> same_chars('abcd', 'dddddddabc')\n True\n >>> same_chars('dddddddabc', 'abcd')\n True\n >>> same_chars('eabcd', 'dddddddabc')\n False\n >>> same_chars('abcd', 'dddddddabce')\n False\n >>> same_chars('eabcdzzzz', 'dddzzzzzzzddddabc')\n False\n \"\"\"\n"} +{"task_id": "HumanEval/55", "completion": "\n\ndef fib(n: int):\n \"\"\"Return n-th Fibonacci number.\n >>> fib(10)\n 55\n >>> fib(1)\n 1\n >>> fib(8)\n 21\n \"\"\"\n"} +{"task_id": "HumanEval/56", "completion": "\n\ndef correct_bracketing(brackets: str):\n \"\"\" brackets is a string of \"<\" and \">\".\n return True if every opening bracket has a corresponding closing bracket.\n\n >>> correct_bracketing(\"<\")\n False\n >>> correct_bracketing(\"<>\")\n True\n >>> correct_bracketing(\"<<><>>\")\n True\n >>> correct_bracketing(\"><<>\")\n False\n \"\"\"\n"} +{"task_id": "HumanEval/57", "completion": "\n\ndef monotonic(l: list):\n \"\"\"Return True is list elements are monotonically increasing or decreasing.\n >>> monotonic([1, 2, 4, 20])\n True\n >>> monotonic([1, 20, 4, 10])\n False\n >>> monotonic([4, 1, 0, -10])\n True\n \"\"\"\n"} +{"task_id": "HumanEval/58", "completion": "\n\ndef common(l1: list, l2: list):\n \"\"\"Return sorted unique common elements for two lists.\n >>> common([1, 4, 3, 34, 653, 2, 5], [5, 7, 1, 5, 9, 653, 121])\n [1, 5, 653]\n >>> common([5, 3, 2, 8], [3, 2])\n [2, 3]\n\n \"\"\"\n"} +{"task_id": "HumanEval/59", "completion": "\n\ndef largest_prime_factor(n: int):\n \"\"\"Return the largest prime factor of n. Assume n > 1 and is not a prime.\n >>> largest_prime_factor(13195)\n 29\n >>> largest_prime_factor(2048)\n 2\n \"\"\"\n"} +{"task_id": "HumanEval/60", "completion": "\n\ndef sum_to_n(n: int):\n \"\"\"sum_to_n is a function that sums numbers from 1 to n.\n >>> sum_to_n(30)\n 465\n >>> sum_to_n(100)\n 5050\n >>> sum_to_n(5)\n 15\n >>> sum_to_n(10)\n 55\n >>> sum_to_n(1)\n 1\n \"\"\"\n"} +{"task_id": "HumanEval/61", "completion": "\n\ndef correct_bracketing(brackets: str):\n \"\"\" brackets is a string of \"(\" and \")\".\n return True if every opening bracket has a corresponding closing bracket.\n\n >>> correct_bracketing(\"(\")\n False\n >>> correct_bracketing(\"()\")\n True\n >>> correct_bracketing(\"(()())\")\n True\n >>> correct_bracketing(\")(()\")\n False\n \"\"\"\n"} +{"task_id": "HumanEval/62", "completion": "\n\ndef derivative(xs: list):\n \"\"\" xs represent coefficients of a polynomial.\n xs[0] + xs[1] * x + xs[2] * x^2 + ....\n Return derivative of this polynomial in the same form.\n >>> derivative([3, 1, 2, 4, 5])\n [1, 4, 12, 20]\n >>> derivative([1, 2, 3])\n [2, 6]\n \"\"\"\n"} +{"task_id": "HumanEval/63", "completion": "\n\ndef fibfib(n: int):\n \"\"\"The FibFib number sequence is a sequence similar to the Fibbonacci sequnece that's defined as follows:\n fibfib(0) == 0\n fibfib(1) == 0\n fibfib(2) == 1\n fibfib(n) == fibfib(n-1) + fibfib(n-2) + fibfib(n-3).\n Please write a function to efficiently compute the n-th element of the fibfib number sequence.\n >>> fibfib(1)\n 0\n >>> fibfib(5)\n 4\n >>> fibfib(8)\n 24\n \"\"\"\n"} +{"task_id": "HumanEval/64", "completion": "\nFIX = \"\"\"\nAdd more test cases.\n\"\"\"\n\ndef vowels_count(s):\n \"\"\"Write a function vowels_count which takes a string representing\n a word as input and returns the number of vowels in the string.\n Vowels in this case are 'a', 'e', 'i', 'o', 'u'. Here, 'y' is also a\n vowel, but only when it is at the end of the given word.\n\n Example:\n >>> vowels_count(\"abcde\")\n 2\n >>> vowels_count(\"ACEDY\")\n 3\n \"\"\"\n"} +{"task_id": "HumanEval/65", "completion": "\ndef circular_shift(x, shift):\n \"\"\"Circular shift the digits of the integer x, shift the digits right by shift\n and return the result as a string.\n If shift > number of digits, return digits reversed.\n >>> circular_shift(12, 1)\n \"21\"\n >>> circular_shift(12, 2)\n \"12\"\n \"\"\"\n"} +{"task_id": "HumanEval/66", "completion": "\ndef digitSum(s):\n \"\"\"Task\n Write a function that takes a string as input and returns the sum of the upper characters only'\n ASCII codes.\n\n Examples:\n digitSum(\"\") => 0\n digitSum(\"abAB\") => 131\n digitSum(\"abcCd\") => 67\n digitSum(\"helloE\") => 69\n digitSum(\"woArBld\") => 131\n digitSum(\"aAaaaXa\") => 153\n \"\"\"\n"} +{"task_id": "HumanEval/67", "completion": "\ndef fruit_distribution(s,n):\n \"\"\"\n In this task, you will be given a string that represents a number of apples and oranges \n that are distributed in a basket of fruit this basket contains \n apples, oranges, and mango fruits. Given the string that represents the total number of \n the oranges and apples and an integer that represent the total number of the fruits \n in the basket return the number of the mango fruits in the basket.\n for examble:\n fruit_distribution(\"5 apples and 6 oranges\", 19) ->19 - 5 - 6 = 8\n fruit_distribution(\"0 apples and 1 oranges\",3) -> 3 - 0 - 1 = 2\n fruit_distribution(\"2 apples and 3 oranges\", 100) -> 100 - 2 - 3 = 95\n fruit_distribution(\"100 apples and 1 oranges\",120) -> 120 - 100 - 1 = 19\n \"\"\"\n"} +{"task_id": "HumanEval/68", "completion": "\ndef pluck(arr):\n \"\"\"\n \"Given an array representing a branch of a tree that has non-negative integer nodes\n your task is to pluck one of the nodes and return it.\n The plucked node should be the node with the smallest even value.\n If multiple nodes with the same smallest even value are found return the node that has smallest index.\n\n The plucked node should be returned in a list, [ smalest_value, its index ],\n If there are no even values or the given array is empty, return [].\n\n Example 1:\n Input: [4,2,3]\n Output: [2, 1]\n Explanation: 2 has the smallest even value, and 2 has the smallest index.\n\n Example 2:\n Input: [1,2,3]\n Output: [2, 1]\n Explanation: 2 has the smallest even value, and 2 has the smallest index. \n\n Example 3:\n Input: []\n Output: []\n \n Example 4:\n Input: [5, 0, 3, 0, 4, 2]\n Output: [0, 1]\n Explanation: 0 is the smallest value, but there are two zeros,\n so we will choose the first zero, which has the smallest index.\n\n Constraints:\n * 1 <= nodes.length <= 10000\n * 0 <= node.value\n \"\"\"\n"} +{"task_id": "HumanEval/69", "completion": "\ndef search(lst):\n '''\n You are given a non-empty list of positive integers. Return the greatest integer that is greater than \n zero, and has a frequency greater than or equal to the value of the integer itself. \n The frequency of an integer is the number of times it appears in the list.\n If no such a value exist, return -1.\n Examples:\n search([4, 1, 2, 2, 3, 1]) == 2\n search([1, 2, 2, 3, 3, 3, 4, 4, 4]) == 3\n search([5, 5, 4, 4, 4]) == -1\n '''\n"} +{"task_id": "HumanEval/70", "completion": "\ndef strange_sort_list(lst):\n '''\n Given list of integers, return list in strange order.\n Strange sorting, is when you start with the minimum value,\n then maximum of the remaining integers, then minimum and so on.\n\n Examples:\n strange_sort_list([1, 2, 3, 4]) == [1, 4, 2, 3]\n strange_sort_list([5, 5, 5, 5]) == [5, 5, 5, 5]\n strange_sort_list([]) == []\n '''\n"} +{"task_id": "HumanEval/71", "completion": "\ndef triangle_area(a, b, c):\n '''\n Given the lengths of the three sides of a triangle. Return the area of\n the triangle rounded to 2 decimal points if the three sides form a valid triangle. \n Otherwise return -1\n Three sides make a valid triangle when the sum of any two sides is greater \n than the third side.\n Example:\n triangle_area(3, 4, 5) == 6.00\n triangle_area(1, 2, 10) == -1\n '''\n"} +{"task_id": "HumanEval/72", "completion": "\ndef will_it_fly(q,w):\n '''\n Write a function that returns True if the object q will fly, and False otherwise.\n The object q will fly if it's balanced (it is a palindromic list) and the sum of its elements is less than or equal the maximum possible weight w.\n\n Example:\n will_it_fly([1, 2], 5) \u279e False \n # 1+2 is less than the maximum possible weight, but it's unbalanced.\n\n will_it_fly([3, 2, 3], 1) \u279e False\n # it's balanced, but 3+2+3 is more than the maximum possible weight.\n\n will_it_fly([3, 2, 3], 9) \u279e True\n # 3+2+3 is less than the maximum possible weight, and it's balanced.\n\n will_it_fly([3], 5) \u279e True\n # 3 is less than the maximum possible weight, and it's balanced.\n '''\n"} +{"task_id": "HumanEval/73", "completion": "\ndef smallest_change(arr):\n \"\"\"\n Given an array arr of integers, find the minimum number of elements that\n need to be changed to make the array palindromic. A palindromic array is an array that\n is read the same backwards and forwards. In one change, you can change one element to any other element.\n\n For example:\n smallest_change([1,2,3,5,4,7,9,6]) == 4\n smallest_change([1, 2, 3, 4, 3, 2, 2]) == 1\n smallest_change([1, 2, 3, 2, 1]) == 0\n \"\"\"\n"} +{"task_id": "HumanEval/74", "completion": "\ndef total_match(lst1, lst2):\n '''\n Write a function that accepts two lists of strings and returns the list that has \n total number of chars in the all strings of the list less than the other list.\n\n if the two lists have the same number of chars, return the first list.\n\n Examples\n total_match([], []) \u279e []\n total_match(['hi', 'admin'], ['hI', 'Hi']) \u279e ['hI', 'Hi']\n total_match(['hi', 'admin'], ['hi', 'hi', 'admin', 'project']) \u279e ['hi', 'admin']\n total_match(['hi', 'admin'], ['hI', 'hi', 'hi']) \u279e ['hI', 'hi', 'hi']\n total_match(['4'], ['1', '2', '3', '4', '5']) \u279e ['4']\n '''\n"} +{"task_id": "HumanEval/75", "completion": "\ndef is_multiply_prime(a):\n \"\"\"Write a function that returns true if the given number is the multiplication of 3 prime numbers\n and false otherwise.\n Knowing that (a) is less then 100. \n Example:\n is_multiply_prime(30) == True\n 30 = 2 * 3 * 5\n \"\"\"\n"} +{"task_id": "HumanEval/76", "completion": "\ndef is_simple_power(x, n):\n \"\"\"Your task is to write a function that returns true if a number x is a simple\n power of n and false in other cases.\n x is a simple power of n if n**int=x\n For example:\n is_simple_power(1, 4) => true\n is_simple_power(2, 2) => true\n is_simple_power(8, 2) => true\n is_simple_power(3, 2) => false\n is_simple_power(3, 1) => false\n is_simple_power(5, 3) => false\n \"\"\"\n"} +{"task_id": "HumanEval/77", "completion": "\ndef iscube(a):\n '''\n Write a function that takes an integer a and returns True \n if this ingeger is a cube of some integer number.\n Note: you may assume the input is always valid.\n Examples:\n iscube(1) ==> True\n iscube(2) ==> False\n iscube(-1) ==> True\n iscube(64) ==> True\n iscube(0) ==> True\n iscube(180) ==> False\n '''\n"} +{"task_id": "HumanEval/78", "completion": "\ndef hex_key(num):\n \"\"\"You have been tasked to write a function that receives \n a hexadecimal number as a string and counts the number of hexadecimal \n digits that are primes (prime number, or a prime, is a natural number \n greater than 1 that is not a product of two smaller natural numbers).\n Hexadecimal digits are 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F.\n Prime numbers are 2, 3, 5, 7, 11, 13, 17,...\n So you have to determine a number of the following digits: 2, 3, 5, 7, \n B (=decimal 11), D (=decimal 13).\n Note: you may assume the input is always correct or empty string, \n and symbols A,B,C,D,E,F are always uppercase.\n Examples:\n For num = \"AB\" the output should be 1.\n For num = \"1077E\" the output should be 2.\n For num = \"ABED1A33\" the output should be 4.\n For num = \"123456789ABCDEF0\" the output should be 6.\n For num = \"2020\" the output should be 2.\n \"\"\"\n"} +{"task_id": "HumanEval/79", "completion": "\ndef decimal_to_binary(decimal):\n \"\"\"You will be given a number in decimal form and your task is to convert it to\n binary format. The function should return a string, with each character representing a binary\n number. Each character in the string will be '0' or '1'.\n\n There will be an extra couple of characters 'db' at the beginning and at the end of the string.\n The extra characters are there to help with the format.\n\n Examples:\n decimal_to_binary(15) # returns \"db1111db\"\n decimal_to_binary(32) # returns \"db100000db\"\n \"\"\"\n"} +{"task_id": "HumanEval/80", "completion": "\ndef is_happy(s):\n \"\"\"You are given a string s.\n Your task is to check if the string is happy or not.\n A string is happy if its length is at least 3 and every 3 consecutive letters are distinct\n For example:\n is_happy(a) => False\n is_happy(aa) => False\n is_happy(abcd) => True\n is_happy(aabb) => False\n is_happy(adb) => True\n is_happy(xyy) => False\n \"\"\"\n"} +{"task_id": "HumanEval/81", "completion": "\ndef numerical_letter_grade(grades):\n \"\"\"It is the last week of the semester and the teacher has to give the grades\n to students. The teacher has been making her own algorithm for grading.\n The only problem is, she has lost the code she used for grading.\n She has given you a list of GPAs for some students and you have to write \n a function that can output a list of letter grades using the following table:\n GPA | Letter grade\n 4.0 A+\n > 3.7 A \n > 3.3 A- \n > 3.0 B+\n > 2.7 B \n > 2.3 B-\n > 2.0 C+\n > 1.7 C\n > 1.3 C-\n > 1.0 D+ \n > 0.7 D \n > 0.0 D-\n 0.0 E\n \n\n Example:\n grade_equation([4.0, 3, 1.7, 2, 3.5]) ==> ['A+', 'B', 'C-', 'C', 'A-']\n \"\"\"\n"} +{"task_id": "HumanEval/82", "completion": "\ndef prime_length(string):\n \"\"\"Write a function that takes a string and returns True if the string\n length is a prime number or False otherwise\n Examples\n prime_length('Hello') == True\n prime_length('abcdcba') == True\n prime_length('kittens') == True\n prime_length('orange') == False\n \"\"\"\n"} +{"task_id": "HumanEval/83", "completion": "\ndef starts_one_ends(n):\n \"\"\"\n Given a positive integer n, return the count of the numbers of n-digit\n positive integers that start or end with 1.\n \"\"\"\n"} +{"task_id": "HumanEval/84", "completion": "\ndef solve(N):\n \"\"\"Given a positive integer N, return the total sum of its digits in binary.\n \n Example\n For N = 1000, the sum of digits will be 1 the output should be \"1\".\n For N = 150, the sum of digits will be 6 the output should be \"110\".\n For N = 147, the sum of digits will be 12 the output should be \"1100\".\n \n Variables:\n @N integer\n Constraints: 0 \u2264 N \u2264 10000.\n Output:\n a string of binary number\n \"\"\"\n"} +{"task_id": "HumanEval/85", "completion": "\ndef add(lst):\n \"\"\"Given a non-empty list of integers lst. add the even elements that are at odd indices..\n\n\n Examples:\n add([4, 2, 6, 7]) ==> 2 \n \"\"\"\n"} +{"task_id": "HumanEval/86", "completion": "\ndef anti_shuffle(s):\n \"\"\"\n Write a function that takes a string and returns an ordered version of it.\n Ordered version of string, is a string where all words (separated by space)\n are replaced by a new word where all the characters arranged in\n ascending order based on ascii value.\n Note: You should keep the order of words and blank spaces in the sentence.\n\n For example:\n anti_shuffle('Hi') returns 'Hi'\n anti_shuffle('hello') returns 'ehllo'\n anti_shuffle('Hello World!!!') returns 'Hello !!!Wdlor'\n \"\"\"\n"} +{"task_id": "HumanEval/87", "completion": "\ndef get_row(lst, x):\n \"\"\"\n You are given a 2 dimensional data, as a nested lists,\n which is similar to matrix, however, unlike matrices,\n each row may contain a different number of columns.\n Given lst, and integer x, find integers x in the list,\n and return list of tuples, [(x1, y1), (x2, y2) ...] such that\n each tuple is a coordinate - (row, columns), starting with 0.\n Sort coordinates initially by rows in ascending order.\n Also, sort coordinates of the row by columns in descending order.\n \n Examples:\n get_row([\n [1,2,3,4,5,6],\n [1,2,3,4,1,6],\n [1,2,3,4,5,1]\n ], 1) == [(0, 0), (1, 4), (1, 0), (2, 5), (2, 0)]\n get_row([], 1) == []\n get_row([[], [1], [1, 2, 3]], 3) == [(2, 2)]\n \"\"\"\n"} +{"task_id": "HumanEval/88", "completion": "\ndef sort_array(array):\n \"\"\"\n Given an array of non-negative integers, return a copy of the given array after sorting,\n you will sort the given array in ascending order if the sum( first index value, last index value) is odd,\n or sort it in descending order if the sum( first index value, last index value) is even.\n\n Note:\n * don't change the given array.\n\n Examples:\n * sort_array([]) => []\n * sort_array([5]) => [5]\n * sort_array([2, 4, 3, 0, 1, 5]) => [0, 1, 2, 3, 4, 5]\n * sort_array([2, 4, 3, 0, 1, 5, 6]) => [6, 5, 4, 3, 2, 1, 0]\n \"\"\"\n"} +{"task_id": "HumanEval/89", "completion": "\ndef encrypt(s):\n \"\"\"Create a function encrypt that takes a string as an argument and\n returns a string encrypted with the alphabet being rotated. \n The alphabet should be rotated in a manner such that the letters \n shift down by two multiplied to two places.\n For example:\n encrypt('hi') returns 'lm'\n encrypt('asdfghjkl') returns 'ewhjklnop'\n encrypt('gf') returns 'kj'\n encrypt('et') returns 'ix'\n \"\"\"\n"} +{"task_id": "HumanEval/90", "completion": "\ndef next_smallest(lst):\n \"\"\"\n You are given a list of integers.\n Write a function next_smallest() that returns the 2nd smallest element of the list.\n Return None if there is no such element.\n \n next_smallest([1, 2, 3, 4, 5]) == 2\n next_smallest([5, 1, 4, 3, 2]) == 2\n next_smallest([]) == None\n next_smallest([1, 1]) == None\n \"\"\"\n"} +{"task_id": "HumanEval/91", "completion": "\ndef is_bored(S):\n \"\"\"\n You'll be given a string of words, and your task is to count the number\n of boredoms. A boredom is a sentence that starts with the word \"I\".\n Sentences are delimited by '.', '?' or '!'.\n \n For example:\n >>> is_bored(\"Hello world\")\n 0\n >>> is_bored(\"The sky is blue. The sun is shining. I love this weather\")\n 1\n \"\"\"\n"} +{"task_id": "HumanEval/92", "completion": "\ndef any_int(x, y, z):\n '''\n Create a function that takes 3 numbers.\n Returns true if one of the numbers is equal to the sum of the other two, and all numbers are integers.\n Returns false in any other cases.\n \n Examples\n any_int(5, 2, 7) \u279e True\n \n any_int(3, 2, 2) \u279e False\n\n any_int(3, -2, 1) \u279e True\n \n any_int(3.6, -2.2, 2) \u279e False\n \n\n \n '''\n"} +{"task_id": "HumanEval/93", "completion": "\ndef encode(message):\n \"\"\"\n Write a function that takes a message, and encodes in such a \n way that it swaps case of all letters, replaces all vowels in \n the message with the letter that appears 2 places ahead of that \n vowel in the english alphabet. \n Assume only letters. \n \n Examples:\n >>> encode('test')\n 'TGST'\n >>> encode('This is a message')\n 'tHKS KS C MGSSCGG'\n \"\"\"\n"} +{"task_id": "HumanEval/94", "completion": "\n\ndef skjkasdkd(lst):\n \"\"\"You are given a list of integers.\n You need to find the largest prime value and return the sum of its digits.\n\n Examples:\n For lst = [0,3,2,1,3,5,7,4,5,5,5,2,181,32,4,32,3,2,32,324,4,3] the output should be 10\n For lst = [1,0,1,8,2,4597,2,1,3,40,1,2,1,2,4,2,5,1] the output should be 25\n For lst = [1,3,1,32,5107,34,83278,109,163,23,2323,32,30,1,9,3] the output should be 13\n For lst = [0,724,32,71,99,32,6,0,5,91,83,0,5,6] the output should be 11\n For lst = [0,81,12,3,1,21] the output should be 3\n For lst = [0,8,1,2,1,7] the output should be 7\n \"\"\"\n"} +{"task_id": "HumanEval/95", "completion": "\ndef check_dict_case(dict):\n \"\"\"\n Given a dictionary, return True if all keys are strings in lower \n case or all keys are strings in upper case, else return False.\n The function should return False is the given dictionary is empty.\n Examples:\n check_dict_case({\"a\":\"apple\", \"b\":\"banana\"}) should return True.\n check_dict_case({\"a\":\"apple\", \"A\":\"banana\", \"B\":\"banana\"}) should return False.\n check_dict_case({\"a\":\"apple\", 8:\"banana\", \"a\":\"apple\"}) should return False.\n check_dict_case({\"Name\":\"John\", \"Age\":\"36\", \"City\":\"Houston\"}) should return False.\n check_dict_case({\"STATE\":\"NC\", \"ZIP\":\"12345\" }) should return True.\n \"\"\"\n"} +{"task_id": "HumanEval/96", "completion": "\ndef count_up_to(n):\n \"\"\"Implement a function that takes an non-negative integer and returns an array of the first n\n integers that are prime numbers and less than n.\n for example:\n count_up_to(5) => [2,3]\n count_up_to(11) => [2,3,5,7]\n count_up_to(0) => []\n count_up_to(20) => [2,3,5,7,11,13,17,19]\n count_up_to(1) => []\n count_up_to(18) => [2,3,5,7,11,13,17]\n \"\"\"\n"} +{"task_id": "HumanEval/97", "completion": "\ndef multiply(a, b):\n \"\"\"Complete the function that takes two integers and returns \n the product of their unit digits.\n Assume the input is always valid.\n Examples:\n multiply(148, 412) should return 16.\n multiply(19, 28) should return 72.\n multiply(2020, 1851) should return 0.\n multiply(14,-15) should return 20.\n \"\"\"\n"} +{"task_id": "HumanEval/98", "completion": "\ndef count_upper(s):\n \"\"\"\n Given a string s, count the number of uppercase vowels in even indices.\n \n For example:\n count_upper('aBCdEf') returns 1\n count_upper('abcdefg') returns 0\n count_upper('dBBE') returns 0\n \"\"\"\n"} +{"task_id": "HumanEval/99", "completion": "\ndef closest_integer(value):\n '''\n Create a function that takes a value (string) representing a number\n and returns the closest integer to it. If the number is equidistant\n from two integers, round it away from zero.\n\n Examples\n >>> closest_integer(\"10\")\n 10\n >>> closest_integer(\"15.3\")\n 15\n\n Note:\n Rounding away from zero means that if the given number is equidistant\n from two integers, the one you should return is the one that is the\n farthest from zero. For example closest_integer(\"14.5\") should\n return 15 and closest_integer(\"-14.5\") should return -15.\n '''\n"} +{"task_id": "HumanEval/100", "completion": "\ndef make_a_pile(n):\n \"\"\"\n Given a positive integer n, you have to make a pile of n levels of stones.\n The first level has n stones.\n The number of stones in the next level is:\n - the next odd number if n is odd.\n - the next even number if n is even.\n Return the number of stones in each level in a list, where element at index\n i represents the number of stones in the level (i+1).\n\n Examples:\n >>> make_a_pile(3)\n [3, 5, 7]\n \"\"\"\n"} +{"task_id": "HumanEval/101", "completion": "\ndef words_string(s):\n \"\"\"\n You will be given a string of words separated by commas or spaces. Your task is\n to split the string into words and return an array of the words.\n \n For example:\n words_string(\"Hi, my name is John\") == [\"Hi\", \"my\", \"name\", \"is\", \"John\"]\n words_string(\"One, two, three, four, five, six\") == [\"One\", \"two\", \"three\", \"four\", \"five\", \"six\"]\n \"\"\"\n"} +{"task_id": "HumanEval/102", "completion": "\ndef choose_num(x, y):\n \"\"\"This function takes two positive numbers x and y and returns the\n biggest even integer number that is in the range [x, y] inclusive. If \n there's no such number, then the function should return -1.\n\n For example:\n choose_num(12, 15) = 14\n choose_num(13, 12) = -1\n \"\"\"\n"} +{"task_id": "HumanEval/103", "completion": "\ndef rounded_avg(n, m):\n \"\"\"You are given two positive integers n and m, and your task is to compute the\n average of the integers from n through m (including n and m). \n Round the answer to the nearest integer and convert that to binary.\n If n is greater than m, return -1.\n Example:\n rounded_avg(1, 5) => \"0b11\"\n rounded_avg(7, 5) => -1\n rounded_avg(10, 20) => \"0b1111\"\n rounded_avg(20, 33) => \"0b11010\"\n \"\"\"\n"} +{"task_id": "HumanEval/104", "completion": "\ndef unique_digits(x):\n \"\"\"Given a list of positive integers x. return a sorted list of all \n elements that hasn't any even digit.\n\n Note: Returned list should be sorted in increasing order.\n \n For example:\n >>> unique_digits([15, 33, 1422, 1])\n [1, 15, 33]\n >>> unique_digits([152, 323, 1422, 10])\n []\n \"\"\"\n"} +{"task_id": "HumanEval/105", "completion": "\ndef by_length(arr):\n \"\"\"\n Given an array of integers, sort the integers that are between 1 and 9 inclusive,\n reverse the resulting array, and then replace each digit by its corresponding name from\n \"One\", \"Two\", \"Three\", \"Four\", \"Five\", \"Six\", \"Seven\", \"Eight\", \"Nine\".\n\n For example:\n arr = [2, 1, 1, 4, 5, 8, 2, 3] \n -> sort arr -> [1, 1, 2, 2, 3, 4, 5, 8] \n -> reverse arr -> [8, 5, 4, 3, 2, 2, 1, 1]\n return [\"Eight\", \"Five\", \"Four\", \"Three\", \"Two\", \"Two\", \"One\", \"One\"]\n \n If the array is empty, return an empty array:\n arr = []\n return []\n \n If the array has any strange number ignore it:\n arr = [1, -1 , 55] \n -> sort arr -> [-1, 1, 55]\n -> reverse arr -> [55, 1, -1]\n return = ['One']\n \"\"\"\n"} +{"task_id": "HumanEval/106", "completion": "\ndef f(n):\n \"\"\" Implement the function f that takes n as a parameter,\n and returns a list of size n, such that the value of the element at index i is the factorial of i if i is even\n or the sum of numbers from 1 to i otherwise.\n i starts from 1.\n the factorial of i is the multiplication of the numbers from 1 to i (1 * 2 * ... * i).\n Example:\n f(5) == [1, 2, 6, 24, 15]\n \"\"\"\n"} +{"task_id": "HumanEval/107", "completion": "\ndef even_odd_palindrome(n):\n \"\"\"\n Given a positive integer n, return a tuple that has the number of even and odd\n integer palindromes that fall within the range(1, n), inclusive.\n\n Example 1:\n\n Input: 3\n Output: (1, 2)\n Explanation:\n Integer palindrome are 1, 2, 3. one of them is even, and two of them are odd.\n\n Example 2:\n\n Input: 12\n Output: (4, 6)\n Explanation:\n Integer palindrome are 1, 2, 3, 4, 5, 6, 7, 8, 9, 11. four of them are even, and 6 of them are odd.\n\n Note:\n 1. 1 <= n <= 10^3\n 2. returned tuple has the number of even and odd integer palindromes respectively.\n \"\"\"\n"} +{"task_id": "HumanEval/108", "completion": "\ndef count_nums(arr):\n \"\"\"\n Write a function count_nums which takes an array of integers and returns\n the number of elements which has a sum of digits > 0.\n If a number is negative, then its first signed digit will be negative:\n e.g. -123 has signed digits -1, 2, and 3.\n >>> count_nums([]) == 0\n >>> count_nums([-1, 11, -11]) == 1\n >>> count_nums([1, 1, 2]) == 3\n \"\"\"\n"} +{"task_id": "HumanEval/109", "completion": "\ndef move_one_ball(arr):\n \"\"\"We have an array 'arr' of N integers arr[1], arr[2], ..., arr[N].The\n numbers in the array will be randomly ordered. Your task is to determine if\n it is possible to get an array sorted in non-decreasing order by performing \n the following operation on the given array:\n You are allowed to perform right shift operation any number of times.\n \n One right shift operation means shifting all elements of the array by one\n position in the right direction. The last element of the array will be moved to\n the starting position in the array i.e. 0th index. \n\n If it is possible to obtain the sorted array by performing the above operation\n then return True else return False.\n If the given array is empty then return True.\n\n Note: The given list is guaranteed to have unique elements.\n\n For Example:\n \n move_one_ball([3, 4, 5, 1, 2])==>True\n Explanation: By performin 2 right shift operations, non-decreasing order can\n be achieved for the given array.\n move_one_ball([3, 5, 4, 1, 2])==>False\n Explanation:It is not possible to get non-decreasing order for the given\n array by performing any number of right shift operations.\n \n \"\"\"\n"} +{"task_id": "HumanEval/110", "completion": "\ndef exchange(lst1, lst2):\n \"\"\"In this problem, you will implement a function that takes two lists of numbers,\n and determines whether it is possible to perform an exchange of elements\n between them to make lst1 a list of only even numbers.\n There is no limit on the number of exchanged elements between lst1 and lst2.\n If it is possible to exchange elements between the lst1 and lst2 to make\n all the elements of lst1 to be even, return \"YES\".\n Otherwise, return \"NO\".\n For example:\n exchange([1, 2, 3, 4], [1, 2, 3, 4]) => \"YES\"\n exchange([1, 2, 3, 4], [1, 5, 3, 4]) => \"NO\"\n It is assumed that the input lists will be non-empty.\n \"\"\"\n"} +{"task_id": "HumanEval/111", "completion": "\ndef histogram(test):\n \"\"\"Given a string representing a space separated lowercase letters, return a dictionary\n of the letter with the most repetition and containing the corresponding count.\n If several letters have the same occurrence, return all of them.\n \n Example:\n histogram('a b c') == {'a': 1, 'b': 1, 'c': 1}\n histogram('a b b a') == {'a': 2, 'b': 2}\n histogram('a b c a b') == {'a': 2, 'b': 2}\n histogram('b b b b a') == {'b': 4}\n histogram('') == {}\n\n \"\"\"\n"} +{"task_id": "HumanEval/112", "completion": "\ndef reverse_delete(s,c):\n \"\"\"Task\n We are given two strings s and c, you have to deleted all the characters in s that are equal to any character in c\n then check if the result string is palindrome.\n A string is called palindrome if it reads the same backward as forward.\n You should return a tuple containing the result string and True/False for the check.\n Example\n For s = \"abcde\", c = \"ae\", the result should be ('bcd',False)\n For s = \"abcdef\", c = \"b\" the result should be ('acdef',False)\n For s = \"abcdedcba\", c = \"ab\", the result should be ('cdedc',True)\n \"\"\"\n"} +{"task_id": "HumanEval/113", "completion": "\ndef odd_count(lst):\n \"\"\"Given a list of strings, where each string consists of only digits, return a list.\n Each element i of the output should be \"the number of odd elements in the\n string i of the input.\" where all the i's should be replaced by the number\n of odd digits in the i'th string of the input.\n\n >>> odd_count(['1234567'])\n [\"the number of odd elements 4n the str4ng 4 of the 4nput.\"]\n >>> odd_count(['3',\"11111111\"])\n [\"the number of odd elements 1n the str1ng 1 of the 1nput.\",\n \"the number of odd elements 8n the str8ng 8 of the 8nput.\"]\n \"\"\"\n"} +{"task_id": "HumanEval/114", "completion": "\ndef minSubArraySum(nums):\n \"\"\"\n Given an array of integers nums, find the minimum sum of any non-empty sub-array\n of nums.\n Example\n minSubArraySum([2, 3, 4, 1, 2, 4]) == 1\n minSubArraySum([-1, -2, -3]) == -6\n \"\"\"\n"} +{"task_id": "HumanEval/115", "completion": "\ndef max_fill(grid, capacity):\n import math\n \"\"\"\n You are given a rectangular grid of wells. Each row represents a single well,\n and each 1 in a row represents a single unit of water.\n Each well has a corresponding bucket that can be used to extract water from it, \n and all buckets have the same capacity.\n Your task is to use the buckets to empty the wells.\n Output the number of times you need to lower the buckets.\n\n Example 1:\n Input: \n grid : [[0,0,1,0], [0,1,0,0], [1,1,1,1]]\n bucket_capacity : 1\n Output: 6\n\n Example 2:\n Input: \n grid : [[0,0,1,1], [0,0,0,0], [1,1,1,1], [0,1,1,1]]\n bucket_capacity : 2\n Output: 5\n \n Example 3:\n Input: \n grid : [[0,0,0], [0,0,0]]\n bucket_capacity : 5\n Output: 0\n\n Constraints:\n * all wells have the same length\n * 1 <= grid.length <= 10^2\n * 1 <= grid[:,1].length <= 10^2\n * grid[i][j] -> 0 | 1\n * 1 <= capacity <= 10\n \"\"\"\n"} +{"task_id": "HumanEval/116", "completion": "\ndef sort_array(arr):\n \"\"\"\n In this Kata, you have to sort an array of non-negative integers according to\n number of ones in their binary representation in ascending order.\n For similar number of ones, sort based on decimal value.\n\n It must be implemented like this:\n >>> sort_array([1, 5, 2, 3, 4]) == [1, 2, 3, 4, 5]\n >>> sort_array([-2, -3, -4, -5, -6]) == [-6, -5, -4, -3, -2]\n >>> sort_array([1, 0, 2, 3, 4]) [0, 1, 2, 3, 4]\n \"\"\"\n"} +{"task_id": "HumanEval/117", "completion": "\ndef select_words(s, n):\n \"\"\"Given a string s and a natural number n, you have been tasked to implement \n a function that returns a list of all words from string s that contain exactly \n n consonants, in order these words appear in the string s.\n If the string s is empty then the function should return an empty list.\n Note: you may assume the input string contains only letters and spaces.\n Examples:\n select_words(\"Mary had a little lamb\", 4) ==> [\"little\"]\n select_words(\"Mary had a little lamb\", 3) ==> [\"Mary\", \"lamb\"]\n select_words(\"simple white space\", 2) ==> []\n select_words(\"Hello world\", 4) ==> [\"world\"]\n select_words(\"Uncle sam\", 3) ==> [\"Uncle\"]\n \"\"\"\n"} +{"task_id": "HumanEval/118", "completion": "\ndef get_closest_vowel(word):\n \"\"\"You are given a word. Your task is to find the closest vowel that stands between \n two consonants from the right side of the word (case sensitive).\n \n Vowels in the beginning and ending doesn't count. Return empty string if you didn't\n find any vowel met the above condition. \n\n You may assume that the given string contains English letter only.\n\n Example:\n get_closest_vowel(\"yogurt\") ==> \"u\"\n get_closest_vowel(\"FULL\") ==> \"U\"\n get_closest_vowel(\"quick\") ==> \"\"\n get_closest_vowel(\"ab\") ==> \"\"\n \"\"\"\n"} +{"task_id": "HumanEval/119", "completion": "\ndef match_parens(lst):\n '''\n You are given a list of two strings, both strings consist of open\n parentheses '(' or close parentheses ')' only.\n Your job is to check if it is possible to concatenate the two strings in\n some order, that the resulting string will be good.\n A string S is considered to be good if and only if all parentheses in S\n are balanced. For example: the string '(())()' is good, while the string\n '())' is not.\n Return 'Yes' if there's a way to make a good string, and return 'No' otherwise.\n\n Examples:\n match_parens(['()(', ')']) == 'Yes'\n match_parens([')', ')']) == 'No'\n '''\n"} +{"task_id": "HumanEval/120", "completion": "\ndef maximum(arr, k):\n \"\"\"\n Given an array arr of integers and a positive integer k, return a sorted list \n of length k with the maximum k numbers in arr.\n\n Example 1:\n\n Input: arr = [-3, -4, 5], k = 3\n Output: [-4, -3, 5]\n\n Example 2:\n\n Input: arr = [4, -4, 4], k = 2\n Output: [4, 4]\n\n Example 3:\n\n Input: arr = [-3, 2, 1, 2, -1, -2, 1], k = 1\n Output: [2]\n\n Note:\n 1. The length of the array will be in the range of [1, 1000].\n 2. The elements in the array will be in the range of [-1000, 1000].\n 3. 0 <= k <= len(arr)\n \"\"\"\n"} +{"task_id": "HumanEval/121", "completion": "\ndef solution(lst):\n \"\"\"Given a non-empty list of integers, return the sum of all of the odd elements that are in even positions.\n \n\n Examples\n solution([5, 8, 7, 1]) ==> 12\n solution([3, 3, 3, 3, 3]) ==> 9\n solution([30, 13, 24, 321]) ==>0\n \"\"\"\n"} +{"task_id": "HumanEval/122", "completion": "\ndef add_elements(arr, k):\n \"\"\"\n Given a non-empty array of integers arr and an integer k, return\n the sum of the elements with at most two digits from the first k elements of arr.\n\n Example:\n\n Input: arr = [111,21,3,4000,5,6,7,8,9], k = 4\n Output: 24 # sum of 21 + 3\n\n Constraints:\n 1. 1 <= len(arr) <= 100\n 2. 1 <= k <= len(arr)\n \"\"\"\n"} +{"task_id": "HumanEval/123", "completion": "\ndef get_odd_collatz(n):\n \"\"\"\n Given a positive integer n, return a sorted list that has the odd numbers in collatz sequence.\n\n The Collatz conjecture is a conjecture in mathematics that concerns a sequence defined\n as follows: start with any positive integer n. Then each term is obtained from the \n previous term as follows: if the previous term is even, the next term is one half of \n the previous term. If the previous term is odd, the next term is 3 times the previous\n term plus 1. The conjecture is that no matter what value of n, the sequence will always reach 1.\n\n Note: \n 1. Collatz(1) is [1].\n 2. returned list sorted in increasing order.\n\n For example:\n get_odd_collatz(5) returns [1, 5] # The collatz sequence for 5 is [5, 16, 8, 4, 2, 1], so the odd numbers are only 1, and 5.\n \"\"\"\n"} +{"task_id": "HumanEval/124", "completion": "\ndef valid_date(date):\n \"\"\"You have to write a function which validates a given date string and\n returns True if the date is valid otherwise False.\n The date is valid if all of the following rules are satisfied:\n 1. The date string is not empty.\n 2. The number of days is not less than 1 or higher than 31 days for months 1,3,5,7,8,10,12. And the number of days is not less than 1 or higher than 30 days for months 4,6,9,11. And, the number of days is not less than 1 or higher than 29 for the month 2.\n 3. The months should not be less than 1 or higher than 12.\n 4. The date should be in the format: mm-dd-yyyy\n\n for example: \n valid_date('03-11-2000') => True\n\n valid_date('15-01-2012') => False\n\n valid_date('04-0-2040') => False\n\n valid_date('06-04-2020') => True\n\n valid_date('06/04/2020') => False\n \"\"\"\n"} +{"task_id": "HumanEval/125", "completion": "\ndef split_words(txt):\n '''\n Given a string of words, return a list of words split on whitespace, if no whitespaces exists in the text you\n should split on commas ',' if no commas exists you should return the number of lower-case letters with odd order in the\n alphabet, ord('a') = 0, ord('b') = 1, ... ord('z') = 25\n Examples\n split_words(\"Hello world!\") \u279e [\"Hello\", \"world!\"]\n split_words(\"Hello,world!\") \u279e [\"Hello\", \"world!\"]\n split_words(\"abcdef\") == 3 \n '''\n"} +{"task_id": "HumanEval/126", "completion": "\ndef is_sorted(lst):\n '''\n Given a list of numbers, return whether or not they are sorted\n in ascending order. If list has more than 1 duplicate of the same\n number, return False. Assume no negative numbers and only integers.\n\n Examples\n is_sorted([5]) \u279e True\n is_sorted([1, 2, 3, 4, 5]) \u279e True\n is_sorted([1, 3, 2, 4, 5]) \u279e False\n is_sorted([1, 2, 3, 4, 5, 6]) \u279e True\n is_sorted([1, 2, 3, 4, 5, 6, 7]) \u279e True\n is_sorted([1, 3, 2, 4, 5, 6, 7]) \u279e False\n is_sorted([1, 2, 2, 3, 3, 4]) \u279e True\n is_sorted([1, 2, 2, 2, 3, 4]) \u279e False\n '''\n"} +{"task_id": "HumanEval/127", "completion": "\ndef intersection(interval1, interval2):\n \"\"\"You are given two intervals,\n where each interval is a pair of integers. For example, interval = (start, end) = (1, 2).\n The given intervals are closed which means that the interval (start, end)\n includes both start and end.\n For each given interval, it is assumed that its start is less or equal its end.\n Your task is to determine whether the length of intersection of these two \n intervals is a prime number.\n Example, the intersection of the intervals (1, 3), (2, 4) is (2, 3)\n which its length is 1, which not a prime number.\n If the length of the intersection is a prime number, return \"YES\",\n otherwise, return \"NO\".\n If the two intervals don't intersect, return \"NO\".\n\n\n [input/output] samples:\n intersection((1, 2), (2, 3)) ==> \"NO\"\n intersection((-1, 1), (0, 4)) ==> \"NO\"\n intersection((-3, -1), (-5, 5)) ==> \"YES\"\n \"\"\"\n"} +{"task_id": "HumanEval/128", "completion": "\ndef prod_signs(arr):\n \"\"\"\n You are given an array arr of integers and you need to return\n sum of magnitudes of integers multiplied by product of all signs\n of each number in the array, represented by 1, -1 or 0.\n Note: return None for empty arr.\n\n Example:\n >>> prod_signs([1, 2, 2, -4]) == -9\n >>> prod_signs([0, 1]) == 0\n >>> prod_signs([]) == None\n \"\"\"\n"} +{"task_id": "HumanEval/129", "completion": "\ndef minPath(grid, k):\n \"\"\"\n Given a grid with N rows and N columns (N >= 2) and a positive integer k, \n each cell of the grid contains a value. Every integer in the range [1, N * N]\n inclusive appears exactly once on the cells of the grid.\n\n You have to find the minimum path of length k in the grid. You can start\n from any cell, and in each step you can move to any of the neighbor cells,\n in other words, you can go to cells which share an edge with you current\n cell.\n Please note that a path of length k means visiting exactly k cells (not\n necessarily distinct).\n You CANNOT go off the grid.\n A path A (of length k) is considered less than a path B (of length k) if\n after making the ordered lists of the values on the cells that A and B go\n through (let's call them lst_A and lst_B), lst_A is lexicographically less\n than lst_B, in other words, there exist an integer index i (1 <= i <= k)\n such that lst_A[i] < lst_B[i] and for any j (1 <= j < i) we have\n lst_A[j] = lst_B[j].\n It is guaranteed that the answer is unique.\n Return an ordered list of the values on the cells that the minimum path go through.\n\n Examples:\n\n Input: grid = [ [1,2,3], [4,5,6], [7,8,9]], k = 3\n Output: [1, 2, 1]\n\n Input: grid = [ [5,9,3], [4,1,6], [7,8,2]], k = 1\n Output: [1]\n \"\"\"\n"} +{"task_id": "HumanEval/130", "completion": "\ndef tri(n):\n \"\"\"Everyone knows Fibonacci sequence, it was studied deeply by mathematicians in \n the last couple centuries. However, what people don't know is Tribonacci sequence.\n Tribonacci sequence is defined by the recurrence:\n tri(1) = 3\n tri(n) = 1 + n / 2, if n is even.\n tri(n) = tri(n - 1) + tri(n - 2) + tri(n + 1), if n is odd.\n For example:\n tri(2) = 1 + (2 / 2) = 2\n tri(4) = 3\n tri(3) = tri(2) + tri(1) + tri(4)\n = 2 + 3 + 3 = 8 \n You are given a non-negative integer number n, you have to a return a list of the \n first n + 1 numbers of the Tribonacci sequence.\n Examples:\n tri(3) = [1, 3, 2, 8]\n \"\"\"\n"} +{"task_id": "HumanEval/131", "completion": "\ndef digits(n):\n \"\"\"Given a positive integer n, return the product of the odd digits.\n Return 0 if all digits are even.\n For example:\n digits(1) == 1\n digits(4) == 0\n digits(235) == 15\n \"\"\"\n"} +{"task_id": "HumanEval/132", "completion": "\ndef is_nested(string):\n '''\n Create a function that takes a string as input which contains only square brackets.\n The function should return True if and only if there is a valid subsequence of brackets \n where at least one bracket in the subsequence is nested.\n\n is_nested('[[]]') \u279e True\n is_nested('[]]]]]]][[[[[]') \u279e False\n is_nested('[][]') \u279e False\n is_nested('[]') \u279e False\n is_nested('[[][]]') \u279e True\n is_nested('[[]][[') \u279e True\n '''\n"} +{"task_id": "HumanEval/133", "completion": "\n\ndef sum_squares(lst):\n \"\"\"You are given a list of numbers.\n You need to return the sum of squared numbers in the given list,\n round each element in the list to the upper int(Ceiling) first.\n Examples:\n For lst = [1,2,3] the output should be 14\n For lst = [1,4,9] the output should be 98\n For lst = [1,3,5,7] the output should be 84\n For lst = [1.4,4.2,0] the output should be 29\n For lst = [-2.4,1,1] the output should be 6\n \n\n \"\"\"\n"} +{"task_id": "HumanEval/134", "completion": "\ndef check_if_last_char_is_a_letter(txt):\n '''\n Create a function that returns True if the last character\n of a given string is an alphabetical character and is not\n a part of a word, and False otherwise.\n Note: \"word\" is a group of characters separated by space.\n\n Examples:\n check_if_last_char_is_a_letter(\"apple pie\") \u279e False\n check_if_last_char_is_a_letter(\"apple pi e\") \u279e True\n check_if_last_char_is_a_letter(\"apple pi e \") \u279e False\n check_if_last_char_is_a_letter(\"\") \u279e False \n '''\n"} +{"task_id": "HumanEval/135", "completion": "\ndef can_arrange(arr):\n \"\"\"Create a function which returns the largest index of an element which\n is not greater than or equal to the element immediately preceding it. If\n no such element exists then return -1. The given array will not contain\n duplicate values.\n\n Examples:\n can_arrange([1,2,4,3,5]) = 3\n can_arrange([1,2,3]) = -1\n \"\"\"\n"} +{"task_id": "HumanEval/136", "completion": "\ndef largest_smallest_integers(lst):\n '''\n Create a function that returns a tuple (a, b), where 'a' is\n the largest of negative integers, and 'b' is the smallest\n of positive integers in a list.\n If there is no negative or positive integers, return them as None.\n\n Examples:\n largest_smallest_integers([2, 4, 1, 3, 5, 7]) == (None, 1)\n largest_smallest_integers([]) == (None, None)\n largest_smallest_integers([0]) == (None, None)\n '''\n"} +{"task_id": "HumanEval/137", "completion": "\ndef compare_one(a, b):\n \"\"\"\n Create a function that takes integers, floats, or strings representing\n real numbers, and returns the larger variable in its given variable type.\n Return None if the values are equal.\n Note: If a real number is represented as a string, the floating point might be . or ,\n\n compare_one(1, 2.5) \u279e 2.5\n compare_one(1, \"2,3\") \u279e \"2,3\"\n compare_one(\"5,1\", \"6\") \u279e \"6\"\n compare_one(\"1\", 1) \u279e None\n \"\"\"\n"} +{"task_id": "HumanEval/138", "completion": "\ndef is_equal_to_sum_even(n):\n \"\"\"Evaluate whether the given number n can be written as the sum of exactly 4 positive even numbers\n Example\n is_equal_to_sum_even(4) == False\n is_equal_to_sum_even(6) == False\n is_equal_to_sum_even(8) == True\n \"\"\"\n"} +{"task_id": "HumanEval/139", "completion": "\ndef special_factorial(n):\n \"\"\"The Brazilian factorial is defined as:\n brazilian_factorial(n) = n! * (n-1)! * (n-2)! * ... * 1!\n where n > 0\n\n For example:\n >>> special_factorial(4)\n 288\n\n The function will receive an integer as input and should return the special\n factorial of this integer.\n \"\"\"\n"} +{"task_id": "HumanEval/140", "completion": "\ndef fix_spaces(text):\n \"\"\"\n Given a string text, replace all spaces in it with underscores, \n and if a string has more than 2 consecutive spaces, \n then replace all consecutive spaces with - \n \n fix_spaces(\"Example\") == \"Example\"\n fix_spaces(\"Example 1\") == \"Example_1\"\n fix_spaces(\" Example 2\") == \"_Example_2\"\n fix_spaces(\" Example 3\") == \"_Example-3\"\n \"\"\"\n"} +{"task_id": "HumanEval/141", "completion": "\ndef file_name_check(file_name):\n \"\"\"Create a function which takes a string representing a file's name, and returns\n 'Yes' if the the file's name is valid, and returns 'No' otherwise.\n A file's name is considered to be valid if and only if all the following conditions \n are met:\n - There should not be more than three digits ('0'-'9') in the file's name.\n - The file's name contains exactly one dot '.'\n - The substring before the dot should not be empty, and it starts with a letter from \n the latin alphapet ('a'-'z' and 'A'-'Z').\n - The substring after the dot should be one of these: ['txt', 'exe', 'dll']\n Examples:\n file_name_check(\"example.txt\") # => 'Yes'\n file_name_check(\"1example.dll\") # => 'No' (the name should start with a latin alphapet letter)\n \"\"\"\n"} +{"task_id": "HumanEval/142", "completion": "\n\n\ndef sum_squares(lst):\n \"\"\"\"\n This function will take a list of integers. For all entries in the list, the function shall square the integer entry if its index is a \n multiple of 3 and will cube the integer entry if its index is a multiple of 4 and not a multiple of 3. The function will not \n change the entries in the list whose indexes are not a multiple of 3 or 4. The function shall then return the sum of all entries. \n \n Examples:\n For lst = [1,2,3] the output should be 6\n For lst = [] the output should be 0\n For lst = [-1,-5,2,-1,-5] the output should be -126\n \"\"\"\n"} +{"task_id": "HumanEval/143", "completion": "\ndef words_in_sentence(sentence):\n \"\"\"\n You are given a string representing a sentence,\n the sentence contains some words separated by a space,\n and you have to return a string that contains the words from the original sentence,\n whose lengths are prime numbers,\n the order of the words in the new string should be the same as the original one.\n\n Example 1:\n Input: sentence = \"This is a test\"\n Output: \"is\"\n\n Example 2:\n Input: sentence = \"lets go for swimming\"\n Output: \"go for\"\n\n Constraints:\n * 1 <= len(sentence) <= 100\n * sentence contains only letters\n \"\"\"\n"} +{"task_id": "HumanEval/144", "completion": "\ndef simplify(x, n):\n \"\"\"Your task is to implement a function that will simplify the expression\n x * n. The function returns True if x * n evaluates to a whole number and False\n otherwise. Both x and n, are string representation of a fraction, and have the following format,\n / where both numerator and denominator are positive whole numbers.\n\n You can assume that x, and n are valid fractions, and do not have zero as denominator.\n\n simplify(\"1/5\", \"5/1\") = True\n simplify(\"1/6\", \"2/1\") = False\n simplify(\"7/10\", \"10/2\") = False\n \"\"\"\n"} +{"task_id": "HumanEval/145", "completion": "\ndef order_by_points(nums):\n \"\"\"\n Write a function which sorts the given list of integers\n in ascending order according to the sum of their digits.\n Note: if there are several items with similar sum of their digits,\n order them based on their index in original list.\n\n For example:\n >>> order_by_points([1, 11, -1, -11, -12]) == [-1, -11, 1, -12, 11]\n >>> order_by_points([]) == []\n \"\"\"\n"} +{"task_id": "HumanEval/146", "completion": "\ndef specialFilter(nums):\n \"\"\"Write a function that takes an array of numbers as input and returns \n the number of elements in the array that are greater than 10 and both \n first and last digits of a number are odd (1, 3, 5, 7, 9).\n For example:\n specialFilter([15, -73, 14, -15]) => 1 \n specialFilter([33, -2, -3, 45, 21, 109]) => 2\n \"\"\"\n"} +{"task_id": "HumanEval/147", "completion": "\ndef get_max_triples(n):\n \"\"\"\n You are given a positive integer n. You have to create an integer array a of length n.\n For each i (1 \u2264 i \u2264 n), the value of a[i] = i * i - i + 1.\n Return the number of triples (a[i], a[j], a[k]) of a where i < j < k, \n and a[i] + a[j] + a[k] is a multiple of 3.\n\n Example :\n Input: n = 5\n Output: 1\n Explanation: \n a = [1, 3, 7, 13, 21]\n The only valid triple is (1, 7, 13).\n \"\"\"\n"} +{"task_id": "HumanEval/148", "completion": "\ndef bf(planet1, planet2):\n '''\n There are eight planets in our solar system: the closerst to the Sun \n is Mercury, the next one is Venus, then Earth, Mars, Jupiter, Saturn, \n Uranus, Neptune.\n Write a function that takes two planet names as strings planet1 and planet2. \n The function should return a tuple containing all planets whose orbits are \n located between the orbit of planet1 and the orbit of planet2, sorted by \n the proximity to the sun. \n The function should return an empty tuple if planet1 or planet2\n are not correct planet names. \n Examples\n bf(\"Jupiter\", \"Neptune\") ==> (\"Saturn\", \"Uranus\")\n bf(\"Earth\", \"Mercury\") ==> (\"Venus\")\n bf(\"Mercury\", \"Uranus\") ==> (\"Venus\", \"Earth\", \"Mars\", \"Jupiter\", \"Saturn\")\n '''\n"} +{"task_id": "HumanEval/149", "completion": "\ndef sorted_list_sum(lst):\n \"\"\"Write a function that accepts a list of strings as a parameter,\n deletes the strings that have odd lengths from it,\n and returns the resulted list with a sorted order,\n The list is always a list of strings and never an array of numbers,\n and it may contain duplicates.\n The order of the list should be ascending by length of each word, and you\n should return the list sorted by that rule.\n If two words have the same length, sort the list alphabetically.\n The function should return a list of strings in sorted order.\n You may assume that all words will have the same length.\n For example:\n assert list_sort([\"aa\", \"a\", \"aaa\"]) => [\"aa\"]\n assert list_sort([\"ab\", \"a\", \"aaa\", \"cd\"]) => [\"ab\", \"cd\"]\n \"\"\"\n"} +{"task_id": "HumanEval/150", "completion": "\ndef x_or_y(n, x, y):\n \"\"\"A simple program which should return the value of x if n is \n a prime number and should return the value of y otherwise.\n\n Examples:\n for x_or_y(7, 34, 12) == 34\n for x_or_y(15, 8, 5) == 5\n \n \"\"\"\n"} +{"task_id": "HumanEval/151", "completion": "\ndef double_the_difference(lst):\n '''\n Given a list of numbers, return the sum of squares of the numbers\n in the list that are odd. Ignore numbers that are negative or not integers.\n \n double_the_difference([1, 3, 2, 0]) == 1 + 9 + 0 + 0 = 10\n double_the_difference([-1, -2, 0]) == 0\n double_the_difference([9, -2]) == 81\n double_the_difference([0]) == 0 \n \n If the input list is empty, return 0.\n '''\n"} +{"task_id": "HumanEval/152", "completion": "\ndef compare(game,guess):\n \"\"\"I think we all remember that feeling when the result of some long-awaited\n event is finally known. The feelings and thoughts you have at that moment are\n definitely worth noting down and comparing.\n Your task is to determine if a person correctly guessed the results of a number of matches.\n You are given two arrays of scores and guesses of equal length, where each index shows a match. \n Return an array of the same length denoting how far off each guess was. If they have guessed correctly,\n the value is 0, and if not, the value is the absolute difference between the guess and the score.\n \n \n example:\n\n compare([1,2,3,4,5,1],[1,2,3,4,2,-2]) -> [0,0,0,0,3,3]\n compare([0,5,0,0,0,4],[4,1,1,0,0,-2]) -> [4,4,1,0,0,6]\n \"\"\"\n"} +{"task_id": "HumanEval/153", "completion": "\ndef Strongest_Extension(class_name, extensions):\n \"\"\"You will be given the name of a class (a string) and a list of extensions.\n The extensions are to be used to load additional classes to the class. The\n strength of the extension is as follows: Let CAP be the number of the uppercase\n letters in the extension's name, and let SM be the number of lowercase letters \n in the extension's name, the strength is given by the fraction CAP - SM. \n You should find the strongest extension and return a string in this \n format: ClassName.StrongestExtensionName.\n If there are two or more extensions with the same strength, you should\n choose the one that comes first in the list.\n For example, if you are given \"Slices\" as the class and a list of the\n extensions: ['SErviNGSliCes', 'Cheese', 'StuFfed'] then you should\n return 'Slices.SErviNGSliCes' since 'SErviNGSliCes' is the strongest extension \n (its strength is -1).\n Example:\n for Strongest_Extension('my_class', ['AA', 'Be', 'CC']) == 'my_class.AA'\n \"\"\"\n"} +{"task_id": "HumanEval/154", "completion": "\ndef cycpattern_check(a , b):\n \"\"\"You are given 2 words. You need to return True if the second word or any of its rotations is a substring in the first word\n cycpattern_check(\"abcd\",\"abd\") => False\n cycpattern_check(\"hello\",\"ell\") => True\n cycpattern_check(\"whassup\",\"psus\") => False\n cycpattern_check(\"abab\",\"baa\") => True\n cycpattern_check(\"efef\",\"eeff\") => False\n cycpattern_check(\"himenss\",\"simen\") => True\n\n \"\"\"\n"} +{"task_id": "HumanEval/155", "completion": "\ndef even_odd_count(num):\n \"\"\"Given an integer. return a tuple that has the number of even and odd digits respectively.\n\n Example:\n even_odd_count(-12) ==> (1, 1)\n even_odd_count(123) ==> (1, 2)\n \"\"\"\n"} +{"task_id": "HumanEval/156", "completion": "\ndef int_to_mini_roman(number):\n \"\"\"\n Given a positive integer, obtain its roman numeral equivalent as a string,\n and return it in lowercase.\n Restrictions: 1 <= num <= 1000\n\n Examples:\n >>> int_to_mini_roman(19) == 'xix'\n >>> int_to_mini_roman(152) == 'clii'\n >>> int_to_mini_roman(426) == 'cdxxvi'\n \"\"\"\n"} +{"task_id": "HumanEval/157", "completion": "\ndef right_angle_triangle(a, b, c):\n '''\n Given the lengths of the three sides of a triangle. Return True if the three\n sides form a right-angled triangle, False otherwise.\n A right-angled triangle is a triangle in which one angle is right angle or \n 90 degree.\n Example:\n right_angle_triangle(3, 4, 5) == True\n right_angle_triangle(1, 2, 3) == False\n '''\n"} +{"task_id": "HumanEval/158", "completion": "\ndef find_max(words):\n \"\"\"Write a function that accepts a list of strings.\n The list contains different words. Return the word with maximum number\n of unique characters. If multiple strings have maximum number of unique\n characters, return the one which comes first in lexicographical order.\n\n find_max([\"name\", \"of\", \"string\"]) == \"string\"\n find_max([\"name\", \"enam\", \"game\"]) == \"enam\"\n find_max([\"aaaaaaa\", \"bb\" ,\"cc\"]) == \"\"aaaaaaa\"\n \"\"\"\n"} +{"task_id": "HumanEval/159", "completion": "\ndef eat(number, need, remaining):\n \"\"\"\n You're a hungry rabbit, and you already have eaten a certain number of carrots,\n but now you need to eat more carrots to complete the day's meals.\n you should return an array of [ total number of eaten carrots after your meals,\n the number of carrots left after your meals ]\n if there are not enough remaining carrots, you will eat all remaining carrots, but will still be hungry.\n \n Example:\n * eat(5, 6, 10) -> [11, 4]\n * eat(4, 8, 9) -> [12, 1]\n * eat(1, 10, 10) -> [11, 0]\n * eat(2, 11, 5) -> [7, 0]\n \n Variables:\n @number : integer\n the number of carrots that you have eaten.\n @need : integer\n the number of carrots that you need to eat.\n @remaining : integer\n the number of remaining carrots thet exist in stock\n \n Constrain:\n * 0 <= number <= 1000\n * 0 <= need <= 1000\n * 0 <= remaining <= 1000\n\n Have fun :)\n \"\"\"\n"} +{"task_id": "HumanEval/160", "completion": "\ndef do_algebra(operator, operand):\n \"\"\"\n Given two lists operator, and operand. The first list has basic algebra operations, and \n the second list is a list of integers. Use the two given lists to build the algebric \n expression and return the evaluation of this expression.\n\n The basic algebra operations:\n Addition ( + ) \n Subtraction ( - ) \n Multiplication ( * ) \n Floor division ( // ) \n Exponentiation ( ** ) \n\n Example:\n operator['+', '*', '-']\n array = [2, 3, 4, 5]\n result = 2 + 3 * 4 - 5\n => result = 9\n\n Note:\n The length of operator list is equal to the length of operand list minus one.\n Operand is a list of of non-negative integers.\n Operator list has at least one operator, and operand list has at least two operands.\n\n \"\"\"\n"} +{"task_id": "HumanEval/161", "completion": "\ndef solve(s):\n \"\"\"You are given a string s.\n if s[i] is a letter, reverse its case from lower to upper or vise versa, \n otherwise keep it as it is.\n If the string contains no letters, reverse the string.\n The function should return the resulted string.\n Examples\n solve(\"1234\") = \"4321\"\n solve(\"ab\") = \"AB\"\n solve(\"#a@C\") = \"#A@c\"\n \"\"\"\n"} +{"task_id": "HumanEval/162", "completion": "\ndef string_to_md5(text):\n \"\"\"\n Given a string 'text', return its md5 hash equivalent string.\n If 'text' is an empty string, return None.\n\n >>> string_to_md5('Hello world') == '3e25960a79dbc69b674cd4ec67a72c62'\n \"\"\"\n"} +{"task_id": "HumanEval/163", "completion": "\ndef generate_integers(a, b):\n \"\"\"\n Given two positive integers a and b, return the even digits between a\n and b, in ascending order.\n\n For example:\n generate_integers(2, 8) => [2, 4, 6, 8]\n generate_integers(8, 2) => [2, 4, 6, 8]\n generate_integers(10, 14) => []\n \"\"\"\n"} diff --git a/experiment/swe_bench/README.md b/experiment/swe_bench/README.md new file mode 100644 index 000000000..c51d6d639 --- /dev/null +++ b/experiment/swe_bench/README.md @@ -0,0 +1,34 @@ +# How to run SWE-Bench + +## Step 0 +Install SWE-Bench as following: +```shell +git clone git@github.com:princeton-nlp/SWE-bench.git +cd SWE-bench +pip install -e . +``` + +## Step 1 +You need to run `inference.py` to get agent output. +Your agent's output needs to be in the following format. +```text +{ + "instance_id": "", + "model_patch": "<.patch file content string>", + "model_name_or_path": "", +} +``` +Collect all agent output as a `.jsonl` or `.json` file. Like `predictions.jsonl`. + +## Step 2 +Run evaluation like this: +```shell +python -m pyopenagi.data.swebench.run_evaluation \ + --dataset_name princeton-nlp/SWE-bench_Lite \ + --predictions_path \ + --max_workers \ + --run_id + # use --predictions_path 'gold' to verify the gold patches + # use --run_id to name the evaluation run +``` +`--predictions_path` is the path of your `predictions.jsonl` diff --git a/experiment/swe_bench/__init__.py b/experiment/swe_bench/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/experiment/swe_bench/inference.py b/experiment/swe_bench/inference.py new file mode 100644 index 000000000..84fd58d97 --- /dev/null +++ b/experiment/swe_bench/inference.py @@ -0,0 +1,114 @@ +import json +import re +from json import JSONDecodeError +from typing import List + +from datasets import load_dataset + +from aios.hooks.starter import aios_starter +from experiment.agent.experiment_agent import ExpirementAgent +from experiment.experiment_core import MetaData, AGENT_TYPE_MAPPING_AIOS, logger, run_inference +from experiment.utils import get_args + + +def parse_patch(agent_result: str): + patterns = [r'```patch\s*([\s\S]*?)```', r'```diff\s*([\s\S]*?)```', r'(.*?)'] + + for pattern in patterns: + match = re.search(pattern, agent_result) + if match: + patch = match.group(1) + return patch + + try: + with open("wrong_result.json", "r", encoding="utf-8") as file: + predictions = json.load(file) + except FileNotFoundError: + predictions = [] + except JSONDecodeError: + predictions = [] + + predictions.append(agent_result) + with open("wrong_result.json", "w", encoding="utf-8") as file: + json.dump(predictions, file, ensure_ascii=False, indent=4) + + return "[None]" + + +def write_prediction(instance_id: str, model_patch: str, model_name_or_path: str, out_path: str): + prediction = { + "instance_id": instance_id, + "model_patch": model_patch, + "model_name_or_path": model_name_or_path, + } + + try: + with open(out_path, "r", encoding="utf-8") as file: + predictions = json.load(file) + except FileNotFoundError: + predictions = [] + except JSONDecodeError: + predictions = [] + + predictions.append(prediction) + + with open(out_path, "w", encoding="utf-8") as file: + json.dump(predictions, file, ensure_ascii=False, indent=4) + + print(f"Write prediction: {prediction}") + + +def write_output_func(result_list: List, output_file: str): + with open(output_file, "w", encoding="utf-8") as file: + json.dump(result_list, file, ensure_ascii=False, indent=4) + logger.log(f"Write results num: {len(result_list)}", level="info") + + +def process_one_func(data, meta_data: MetaData): + if meta_data.on_aios: + with aios_starter(**meta_data.aios_args): + agent: ExpirementAgent = AGENT_TYPE_MAPPING_AIOS[meta_data.agent_type](meta_data.on_aios) + input_str = data["text"] + result = agent.run(input_str) + patch = parse_patch(result) + + prediction = { + "instance_id": data["instance_id"], + "model_patch": patch, + "model_name_or_path": meta_data.agent_type, + } + return prediction + else: + agent: ExpirementAgent = AGENT_TYPE_MAPPING_AIOS[meta_data.agent_type](meta_data.on_aios) + input_str = data["text"] + result = agent.run(input_str) + patch = parse_patch(result) + + prediction = { + "instance_id": data["instance_id"], + "model_patch": patch, + "model_name_or_path": meta_data.agent_type, + } + return prediction + + +if __name__ == '__main__': + main_args, global_args = get_args() + + agent_type = "swe:" + main_args.agent_type + dataset = load_dataset(main_args.data_name, split=main_args.split) + + meta = MetaData( + dataset=dataset, + agent_type=agent_type, + output_file=main_args.output_file, + on_aios=main_args.on_aios, + max_num=main_args.max_num, + aios_args=vars(global_args), + ) + + run_inference( + meta_data=meta, + process_one_func=process_one_func, + write_output_func=write_output_func + ) diff --git a/experiment/swe_bench/requirements.txt b/experiment/swe_bench/requirements.txt new file mode 100644 index 000000000..5801109e2 --- /dev/null +++ b/experiment/swe_bench/requirements.txt @@ -0,0 +1,2 @@ +sentencepiece +tiktoken diff --git a/experiment/swe_bench/run_evaluation.py b/experiment/swe_bench/run_evaluation.py new file mode 100644 index 000000000..ece057116 --- /dev/null +++ b/experiment/swe_bench/run_evaluation.py @@ -0,0 +1,35 @@ +from argparse import ArgumentParser + +from swebench.harness.utils import str2bool +from swebench.harness.run_evaluation import main + +if __name__ == "__main__": + parser = ArgumentParser() + parser.add_argument("--dataset_name", default="princeton-nlp/SWE-bench_Lite", type=str, help="Name of dataset or path to JSON file.") + parser.add_argument("--split", type=str, default="test", help="Split of the dataset") + parser.add_argument("--instance_ids", nargs="+", type=str, help="Instance IDs to run (space separated)") + parser.add_argument("--predictions_path", type=str, help="Path to predictions file - if 'gold', uses gold predictions", required=True) + parser.add_argument("--max_workers", type=int, default=4, help="Maximum number of workers (should be <= 75%% of CPU cores)") + parser.add_argument("--open_file_limit", type=int, default=4096, help="Open file limit") + parser.add_argument( + "--timeout", type=int, default=1_800, help="Timeout (in seconds) for running tests for each instance" + ) + parser.add_argument( + "--force_rebuild", type=str2bool, default=False, help="Force rebuild of all images" + ) + parser.add_argument( + "--cache_level", + type=str, + choices=["none", "base", "env", "instance"], + help="Cache level - remove images above this level", + default="env", + ) + # if clean is true then we remove all images that are above the cache level + # if clean is false, we only remove images above the cache level if they don't already exist + parser.add_argument( + "--clean", type=str2bool, default=False, help="Clean images above cache level" + ) + parser.add_argument("--run_id", type=str, required=True, help="Run ID - identifies the run") + args = parser.parse_args() + + main(**vars(args)) diff --git a/experiment/swe_bench/run_with_aios.sh b/experiment/swe_bench/run_with_aios.sh new file mode 100644 index 000000000..6ec006d69 --- /dev/null +++ b/experiment/swe_bench/run_with_aios.sh @@ -0,0 +1,8 @@ +python -m experiment.humaneval.inference \ + --data_name openai/openai_humaneval \ + --split test \ + --output_file experiment/swe_bench/eval_prediction.json \ + --on_aios \ + --agent_type interpreter \ + --llm_name gpt-4o-mini \ + --max_new_tokens 8000 \ No newline at end of file diff --git a/experiment/utils.py b/experiment/utils.py new file mode 100644 index 000000000..e6d37a34b --- /dev/null +++ b/experiment/utils.py @@ -0,0 +1,20 @@ +import argparse + +from aios.utils.utils import parse_global_args + + +def get_args(): + parser = parse_global_args() + + main_parser = argparse.ArgumentParser() + main_parser.add_argument("--agent_type", type=str, default="interpreter") + main_parser.add_argument("--data_name", type=str, default="gaia-benchmark/GAIA") + main_parser.add_argument("--split", type=str, default="test") + main_parser.add_argument("--output_file", type=str, default="prediction.json") + main_parser.add_argument("--on_aios", action="store_true") + main_parser.add_argument("--max_num", type=int, default=None) + + global_args, remaining_args = parser.parse_known_args() + main_args = main_parser.parse_args(remaining_args) + + return main_args, global_args diff --git a/main.py b/main.py index 083d042e1..66648fdb0 100644 --- a/main.py +++ b/main.py @@ -7,7 +7,7 @@ import os import warnings -from aios.hooks.llm import aios_starter +from aios.hooks.starter import aios_starter from aios.utils.utils import delete_directories from dotenv import load_dotenv diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..3d9a5ada6 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "AIOS", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} From 6e42b336da699a073b0aa98db08e14a9e00abd26 Mon Sep 17 00:00:00 2001 From: dongyuanjushi Date: Thu, 31 Oct 2024 07:26:36 -0400 Subject: [PATCH 22/41] update README --- experiment/humaneval/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experiment/humaneval/README.md b/experiment/humaneval/README.md index 6145bf405..971eebdab 100644 --- a/experiment/humaneval/README.md +++ b/experiment/humaneval/README.md @@ -3,7 +3,7 @@ python -m experiment.humaneval.inference \ --data_name openai/openai_humaneval \ --split test \ - --output_file experiment/humaneval_prediction.json \ + --output_file experiment/interpreter_predictions.jsonl \ --on_aios \ # --max_num 1 \ --agent_type interpreter \ From df481b9f25098b2d9aedf11e3f4ad59b170ecd33 Mon Sep 17 00:00:00 2001 From: dongyuanjushi Date: Thu, 31 Oct 2024 07:26:48 -0400 Subject: [PATCH 23/41] update README --- README.md | 52 ---------------------------------------------------- 1 file changed, 52 deletions(-) diff --git a/README.md b/README.md index 2d193bbc6..cfa4c9041 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,4 @@ # AIOS: LLM Agent Operating System - - - - -[![Code License](https://img.shields.io/badge/Code%20License-MIT-orange.svg)](https://github.com/agiresearch/AIOS/blob/main/LICENSE) - - -agiresearch%2FAIOS | Trendshift - The goal of AIOS is to build a large language model (LLM) agent operating system, which intends to embed large language model into the operating system as the brain of the OS. AIOS is designed to address problems (e.g., scheduling, context switch, memory management, etc.) during the development and deployment of LLM-based agents, for a better ecosystem among agent developers and users. ## 🏠 Architecture of AIOS @@ -17,19 +8,6 @@ The goal of AIOS is to build a large language model (LLM) agent operating system AIOS provides the LLM kernel as an abstraction on top of the OS kernel. The kernel facilitates the installation, execution and usage of agents. Furthermore, the AIOS SDK facilitates the development and deployment of agents. -## 📰 News -- **[2024-09-01]** 🔥 AIOS supports multiple agent creation frameworks (e.g., ReAct, Reflexion, OpenAGI, AutoGen, Open Interpreter, MetaGPT). Agents created by these frameworks can onboard AIOS. Onboarding guidelines can be found at the [Doc](https://aios.readthedocs.io/). -- **[2024-07-10]** 📖 AIOS documentation template is up: [Code](https://github.com/agiresearch/AIOS/tree/main/docs) and [Website](https://aios.readthedocs.io/). -- **[2024-06-20]** 🔥 Function calling for open-sourced LLMs (native huggingface, vllm, ollama) is supported. -- **[2024-05-20]** 🚀 More agents with ChatGPT-based tool calling are added (i.e., MathAgent, RecAgent, TravelAgent, AcademicAgent and CreationAgent), their profiles and workflows can be found in [OpenAGI](https://github.com/agiresearch/OpenAGI). -- **[2024-05-13]** 🛠️ Local models (diffusion models) as tools from HuggingFace are integrated. -- **[2024-05-01]** 🛠️ The agent creation in AIOS is refactored, which can be found in our [OpenAGI](https://github.com/agiresearch/OpenAGI) package. -- **[2024-04-05]** 🛠️ AIOS currently supports external tool callings (google search, wolframalpha, rapid API, etc). -- **[2024-04-02]** 🤝 AIOS [Discord Community](https://discord.gg/B2HFxEgTJX) is up. Welcome to join the community for discussions, brainstorming, development, or just random chats! For how to contribute to AIOS, please see [CONTRIBUTE](https://github.com/agiresearch/AIOS/blob/main/CONTRIBUTE.md). -- **[2024-03-25]** ✈️ Our paper [AIOS: LLM Agent Operating System](https://arxiv.org/abs/2403.16971) is released! -- **[2023-12-06]** 📋 After several months of working, our perspective paper [LLM as OS, Agents as Apps: Envisioning AIOS, Agents and the AIOS-Agent Ecosystem](https://arxiv.org/abs/2312.03815) is officially released. - - ## ✈️ Getting Started Please see our ongoing [documentation](https://aios.readthedocs.io/en/latest/) for more information. - [Installation](https://aios.readthedocs.io/en/latest/get_started/installation.html) @@ -211,33 +189,3 @@ Interact with all agents by using the `@` to tag an agent. - [ollama](https://ollama.com/) - [vllm](https://docs.vllm.ai/en/stable/) - [native huggingface models (locally)](https://huggingface.co/) - -## 🖋️ References -``` -@article{mei2024aios, - title={AIOS: LLM Agent Operating System}, - author={Mei, Kai and Li, Zelong and Xu, Shuyuan and Ye, Ruosong and Ge, Yingqiang and Zhang, Yongfeng} - journal={arXiv:2403.16971}, - year={2024} -} -@article{ge2023llm, - title={LLM as OS, Agents as Apps: Envisioning AIOS, Agents and the AIOS-Agent Ecosystem}, - author={Ge, Yingqiang and Ren, Yujie and Hua, Wenyue and Xu, Shuyuan and Tan, Juntao and Zhang, Yongfeng}, - journal={arXiv:2312.03815}, - year={2023} -} -``` - -## 🚀 Contributions -For how to contribute, see [CONTRIBUTE](https://github.com/agiresearch/AIOS/blob/main/CONTRIBUTE.md). If you would like to contribute to the codebase, [issues](https://github.com/agiresearch/AIOS/issues) or [pull requests](https://github.com/agiresearch/AIOS/pulls) are always welcome! - -## 🌍 AIOS Contributors -[![AIOS contributors](https://contrib.rocks/image?repo=agiresearch/AIOS&max=300)](https://github.com/agiresearch/AIOS/graphs/contributors) - - -## 🤝 Discord Channel -If you would like to join the community, ask questions, chat with fellows, learn about or propose new features, and participate in future developments, join our [Discord Community](https://discord.gg/B2HFxEgTJX)! - -## 📪 Contact - -For issues related to AIOS development, we encourage submitting [issues](https://github.com/agiresearch/AIOS/issues), [pull requests](https://github.com/agiresearch/AIOS/pulls), or initiating discussions in AIOS [Discord Channel](https://discord.gg/B2HFxEgTJX). For other issues please feel free to contact AIOS Foundation ([contact@aios.foundation](mailto:contact@aios.foundation)). From 64a01fe661d2e673365eee299d84c1b01f687502 Mon Sep 17 00:00:00 2001 From: dongyuanjushi Date: Thu, 31 Oct 2024 07:31:05 -0400 Subject: [PATCH 24/41] update --- README.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/README.md b/README.md index cfa4c9041..596d38b2e 100644 --- a/README.md +++ b/README.md @@ -2,16 +2,9 @@ The goal of AIOS is to build a large language model (LLM) agent operating system, which intends to embed large language model into the operating system as the brain of the OS. AIOS is designed to address problems (e.g., scheduling, context switch, memory management, etc.) during the development and deployment of LLM-based agents, for a better ecosystem among agent developers and users. ## 🏠 Architecture of AIOS -

    - -

    - AIOS provides the LLM kernel as an abstraction on top of the OS kernel. The kernel facilitates the installation, execution and usage of agents. Furthermore, the AIOS SDK facilitates the development and deployment of agents. ## ✈️ Getting Started -Please see our ongoing [documentation](https://aios.readthedocs.io/en/latest/) for more information. -- [Installation](https://aios.readthedocs.io/en/latest/get_started/installation.html) -- [Quickstart](https://aios.readthedocs.io/en/latest/get_started/quickstart.html) ### Installation From 5df6d1ecb63ae0b6a6c65720f8af24902fd27bd1 Mon Sep 17 00:00:00 2001 From: dongyuanjushi Date: Fri, 1 Nov 2024 15:52:53 -0400 Subject: [PATCH 25/41] update --- aios/scheduler/fifo_scheduler.py | 10 +- aios/storage/db_storage.py | 63 +- aios/tool/base.py | 4 +- experiment/agent/interpreter.py | 12 +- experiment/humaneval/bash_with_aios.sh | 10 + .../humaneval/interpreter_prediction.json | 658 ------------------ .../humaneval/interpreter_prediction.jsonl | 328 ++++----- ...interpreter_prediction.jsonl_results.jsonl | 164 +++++ 8 files changed, 404 insertions(+), 845 deletions(-) delete mode 100644 experiment/humaneval/interpreter_prediction.json create mode 100644 experiment/humaneval/interpreter_prediction.jsonl_results.jsonl diff --git a/aios/scheduler/fifo_scheduler.py b/aios/scheduler/fifo_scheduler.py index a6927003b..03f9b0d1c 100644 --- a/aios/scheduler/fifo_scheduler.py +++ b/aios/scheduler/fifo_scheduler.py @@ -20,7 +20,9 @@ class FIFOScheduler: def __init__( self, llm, - # memory_manager, + memory_manager, + storage_manager, + tool_manager, log_mode, get_llm_request: LLMRequestQueueGetMessage, get_memory_request: MemoryRequestQueueGetMessage, @@ -35,16 +37,16 @@ def __init__( self.active = False # start/stop the scheduler self.log_mode = log_mode self.logger = self.setup_logger() - # self.thread = Thread(target=self.run) self.request_processors = { "llm_syscall_processor": Thread(target=self.run_llm_request), "mem_syscall_processor": Thread(target=self.run_memory_request), "sto_syscall_processor": Thread(target=self.run_storage_request), "tool_syscall_processor": Thread(target=self.run_tool_request) - # "memory_request_processor": Thread(self.run_memory_request) } self.llm = llm - # self.memory_manager = memory_manager + self.memory_manager = memory_manager + self.storage_manager = storage_manager + self.tool_manager = tool_manager def start(self): """start the scheduler""" diff --git a/aios/storage/db_storage.py b/aios/storage/db_storage.py index 3c17d47f6..033a68ab3 100644 --- a/aios/storage/db_storage.py +++ b/aios/storage/db_storage.py @@ -3,19 +3,60 @@ from aios.storage.base import BaseStorage +import zlib +import pickle +import os -class DBStorage(BaseStorage): - def __init__(self): - pass +class StorageManager: + def __init__(self, storage_path="persistent_storage", vector_db=None): + self.storage_path = storage_path + os.makedirs(self.storage_path, exist_ok=True) + self.vector_db = vector_db # Reference to the ChromaDB instance - def sto_save(self, agent_id, content): - pass + def sto_create(self, aname): + """Creates a new storage file and initializes a collection in vector_db for the agent.""" + file_path = os.path.join(self.storage_path, f"{aname}.dat") + if not os.path.exists(file_path): + with open(file_path, "wb") as file: + file.write(b"") + # Create a collection in the vector database for this agent + if self.vector_db: + self.vector_db.create_collection(aname) - def sto_load(self, agent_id): - pass + def sto_read(self, aname): + """Reads and decompresses data for a specific agent from the physical storage file.""" + file_path = os.path.join(self.storage_path, f"{aname}.dat") + if os.path.exists(file_path): + with open(file_path, "rb") as file: + compressed_data = file.read() + return pickle.loads(zlib.decompress(compressed_data)) if compressed_data else None + return None - def sto_alloc(self, agent_id): - pass + def sto_write(self, aname, s): + """Writes data both to a file and to the vector database.""" + # Write data to physical file storage + file_path = os.path.join(self.storage_path, f"{aname}.dat") + with open(file_path, "ab") as file: # Append mode + compressed_data = zlib.compress(pickle.dumps(s)) + file.write(compressed_data) + + # Append data to the vector database, if available + if self.vector_db: + self.vector_db.add(aname, s) # Assuming vector_db.add method supports appending data by agent name + + def sto_clear(self, aname): + """Clears the physical file storage and deletes the vector database collection for an agent.""" + file_path = os.path.join(self.storage_path, f"{aname}.dat") + if os.path.exists(file_path): + os.remove(file_path) + + # Clear data from vector database if available + if self.vector_db: + self.vector_db.delete(aname) + + def sto_retrieve(self, aname, query): + """Retrieves data from the vector database based on agent name and a query.""" + if self.vector_db: + return self.vector_db.retrieve(aname, query) + return None - def sto_clear(self, agent_id): - pass diff --git a/aios/tool/base.py b/aios/tool/base.py index f82a4b933..87ec69173 100644 --- a/aios/tool/base.py +++ b/aios/tool/base.py @@ -8,8 +8,8 @@ def __init__( self.log_mode = log_mode self.tool_conflict_map = {} - def address_request(self, agent_request, temperature=0.0) -> None: - request_data = agent_request.request_data + def tool_run(self, syscall, temperature=0.0) -> None: + request_data = syscall.request_data tool_org_and_name, tool_params = request_data["name"], request_data["paramemters"] org, tool_name = tool_org_and_name.split("/") diff --git a/experiment/agent/interpreter.py b/experiment/agent/interpreter.py index ed013a5a3..20d1aafbf 100644 --- a/experiment/agent/interpreter.py +++ b/experiment/agent/interpreter.py @@ -63,14 +63,14 @@ def run(self, input_str: str): class InterpreterAgentHumanEval(ExpirementAgent): - SYSTEM_PROMPT = """You will receive a function definition and comments. You need to help me complete this function. - + SYSTEM_PROMPT = """You are an expert good at solving code problems. + You will receive a function definition and comments. You need to help me complete this function. Give me final output in the format: - YOUR FINAL ANSWER (YOUR FINAL ANSWER must be a piece of code that you want to add. The final result must remove - the function definition and function description provided in the problem statement, as well as any unit test - code you added.) - """ + YOUR FINAL ANSWER (YOUR FINAL ANSWER must be a piece of code that you want to add. Just + contains what you add, don't contains the original definition and comments in your code. ) + + """ def __init__(self, on_aios: bool = True): if on_aios: diff --git a/experiment/humaneval/bash_with_aios.sh b/experiment/humaneval/bash_with_aios.sh index 697082f1b..4ea1a175e 100644 --- a/experiment/humaneval/bash_with_aios.sh +++ b/experiment/humaneval/bash_with_aios.sh @@ -5,4 +5,14 @@ python -m experiment.humaneval.inference \ --on_aios \ --agent_type autogen \ --llm_name gpt-4o-mini \ + --max_new_tokens 8000 + + +python -m experiment.humaneval.inference \ + --data_name openai/openai_humaneval \ + --split test \ + --output_file experiment/humaneval/interpreter_prediction.jsonl \ + --on_aios \ + --agent_type interpreter \ + --llm_name gpt-4o-mini \ --max_new_tokens 8000 \ No newline at end of file diff --git a/experiment/humaneval/interpreter_prediction.json b/experiment/humaneval/interpreter_prediction.json deleted file mode 100644 index ae382b25a..000000000 --- a/experiment/humaneval/interpreter_prediction.json +++ /dev/null @@ -1,658 +0,0 @@ -[ - { - "task_id": "HumanEval/0", - "result": "for i in range(len(numbers)):\n for j in range(i + 1, len(numbers)):\n if abs(numbers[i] - numbers[j]) < threshold:\n return True\n return False\n" - }, - { - "task_id": "HumanEval/1", - "result": "def separate_paren_groups(paren_string: str) -> List[str]:\n paren_string = paren_string.replace(\" \", \"\") # Step 1: Remove spaces\n result = []\n stack = []\n current_group = []\n\n for char in paren_string:\n if char == '(':\n if not stack: # Starting a new group\n current_group = [] # Reset current group\n stack.append(char)\n current_group.append(char) # Add to current group\n elif char == ')':\n stack.pop()\n current_group.append(char) # Add to current group\n if not stack: # If stack is empty, a complete group is found\n result.append(''.join(current_group)) # Add to result\n\n return result\n" - }, - { - "task_id": "HumanEval/2", - "result": "def truncate_number(number: float) -> float:\n return number - int(number)\n" - }, - { - "task_id": "HumanEval/3", - "result": "def below_zero(operations: List[int]) -> bool:\n balance = 0\n for operation in operations:\n balance += operation\n if balance < 0:\n return True\n return False\n" - }, - { - "task_id": "HumanEval/4", - "result": "mean_value = sum(numbers) / len(numbers) # Calculate mean\ndeviations = [abs(x - mean_value) for x in numbers] # Calculate absolute differences\nreturn sum(deviations) / len(deviations) # Calculate and return MAD\n" - }, - { - "task_id": "HumanEval/5", - "result": "def intersperse(numbers: List[int], delimeter: int) -> List[int]:\n if not numbers:\n return []\n \n result = []\n for i in range(len(numbers)):\n result.append(numbers[i])\n if i < len(numbers) - 1: # Don't add delimeter after the last element\n result.append(delimeter)\n \n return result\n" - }, - { - "task_id": "HumanEval/6", - "result": "def parse_nested_parens(paren_string: str) -> List[int]:\n depths = []\n groups = paren_string.split()\n\n for group in groups:\n max_depth = 0\n current_depth = 0\n \n for char in group:\n if char == '(':\n current_depth += 1\n max_depth = max(max_depth, current_depth)\n elif char == ')':\n current_depth -= 1\n \n depths.append(max_depth)\n\n return depths\n" - }, - { - "task_id": "HumanEval/7", - "result": "return [s for s in strings if substring in s]\n" - }, - { - "task_id": "HumanEval/8", - "result": "def sum_product(numbers: List[int]) -> Tuple[int, int]:\n total_sum = sum(numbers)\n total_product = 1\n for number in numbers:\n total_product *= number\n return total_sum, total_product\n" - }, - { - "task_id": "HumanEval/9", - "result": "def rolling_max(numbers: List[int]) -> List[int]:\n max_so_far = float('-inf')\n rolling_max_list = []\n\n for number in numbers:\n if number > max_so_far:\n max_so_far = number\n rolling_max_list.append(max_so_far)\n\n return rolling_max_list\n" - }, - { - "task_id": "HumanEval/10", - "result": "def make_palindrome(string: str) -> str:\n def is_palindrome(s: str) -> bool:\n return s == s[::-1]\n\n for i in range(len(string)):\n if is_palindrome(string[i:]):\n return string + string[:i][::-1]\n \n return string\n" - }, - { - "task_id": "HumanEval/11", - "result": "result = ''.join(str(int(x) ^ int(y)) for x, y in zip(a, b))\n" - }, - { - "task_id": "HumanEval/12", - "result": "def longest(strings: List[str]) -> Optional[str]:\n if not strings:\n return None\n longest_string = \"\"\n for string in strings:\n if len(string) > len(longest_string):\n longest_string = string\n return longest_string\n" - }, - { - "task_id": "HumanEval/13", - "result": "def greatest_common_divisor(a: int, b: int) -> int:\n while b:\n a, b = b, a % b\n return a\n" - }, - { - "task_id": "HumanEval/14", - "result": "return [string[:i] for i in range(1, len(string) + 1)]\n" - }, - { - "task_id": "HumanEval/15", - "result": "return ' '.join(str(i) for i in range(n + 1))\n" - }, - { - "task_id": "HumanEval/16", - "result": "return len(set(string.lower()))\n" - }, - { - "task_id": "HumanEval/17", - "result": "def parse_music(music_string: str) -> List[int]:\n note_duration_map = {\n 'o': 4,\n 'o|': 2,\n '.|': 1\n }\n \n notes = music_string.split()\n durations = [note_duration_map[note] for note in notes]\n \n return durations\n" - }, - { - "task_id": "HumanEval/18", - "result": "def how_many_times(string: str, substring: str) -> int:\n count = 0\n start = 0\n\n while True:\n start = string.find(substring, start)\n if start == -1:\n break\n count += 1\n start += 1 # Move to the next character to allow for overlapping\n\n return count\n" - }, - { - "task_id": "HumanEval/19", - "result": "def sort_numbers(numbers: str) -> str:\n number_map = {\n 'zero': 0,\n 'one': 1,\n 'two': 2,\n 'three': 3,\n 'four': 4,\n 'five': 5,\n 'six': 6,\n 'seven': 7,\n 'eight': 8,\n 'nine': 9\n }\n \n words = numbers.split()\n sorted_numbers = sorted(words, key=lambda x: number_map[x])\n return ' '.join(sorted_numbers)\n" - }, - { - "task_id": "HumanEval/20", - "result": "def find_closest_elements(numbers: List[float]) -> Tuple[float, float]:\n numbers.sort()\n closest_pair = (numbers[0], numbers[1])\n min_diff = abs(numbers[1] - numbers[0])\n \n for i in range(1, len(numbers) - 1):\n diff = abs(numbers[i + 1] - numbers[i])\n if diff < min_diff:\n min_diff = diff\n closest_pair = (numbers[i], numbers[i + 1])\n \n return closest_pair\n" - }, - { - "task_id": "HumanEval/21", - "result": "return [(num - min_val) / (max_val - min_val) for num in numbers]\n" - }, - { - "task_id": "HumanEval/22", - "result": "return [value for value in values if isinstance(value, int)]\n" - }, - { - "task_id": "HumanEval/23", - "result": "return len(string)\n" - }, - { - "task_id": "HumanEval/24", - "result": "for i in range(n - 1, 0, -1):\n if n % i == 0:\n return i\n" - }, - { - "task_id": "HumanEval/25", - "result": "def factorize(n: int) -> List[int]:\n factors = []\n while n % 2 == 0:\n factors.append(2)\n n //= 2\n for i in range(3, int(n**0.5) + 1, 2):\n while n % i == 0:\n factors.append(i)\n n //= i\n if n > 2:\n factors.append(n)\n return factors\n" - }, - { - "task_id": "HumanEval/26", - "result": "def remove_duplicates(numbers: List[int]) -> List[int]:\n counts = {}\n for number in numbers:\n counts[number] = counts.get(number, 0) + 1\n \n return [number for number in numbers if counts[number] == 1]\n" - }, - { - "task_id": "HumanEval/27", - "result": "return string.swapcase()\n" - }, - { - "task_id": "HumanEval/28", - "result": "def concatenate(strings: List[str]) -> str:\n return ''.join(strings)\n" - }, - { - "task_id": "HumanEval/29", - "result": "def filter_by_prefix(strings: List[str], prefix: str) -> List[str]:\n return [s for s in strings if s.startswith(prefix)]\n" - }, - { - "task_id": "HumanEval/30", - "result": "def get_positive(l: list):\n return [num for num in l if num > 0]\n" - }, - { - "task_id": "HumanEval/31", - "result": "def is_prime(n):\n if n < 2:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n" - }, - { - "task_id": "HumanEval/32", - "result": "def find_zero(xs: list):\n \"\"\" xs are coefficients of a polynomial. \n find_zero finds x such that poly(x) = 0.\n \"\"\"\n # Contains the polynomial function\n def poly_derivative(xs, x):\n \"\"\" Evaluates the derivative of polynomial with coefficients xs at point x. \"\"\"\n return sum([i * coeff * math.pow(x, i - 1) for i, coeff in enumerate(xs) if i > 0])\n\n # Starting guess can be 0\n x0 = 0.0\n tolerance = 1e-7\n max_iterations = 1000\n for _ in range(max_iterations):\n fx = poly(xs, x0)\n dfx = poly_derivative(xs, x0)\n \n if dfx == 0: # Prevent division by zero\n break\n \n x1 = x0 - fx / dfx\n if abs(x1 - x0) < tolerance: # Check for convergence\n return x1\n x0 = x1\n \n return x0 # Return the last approximation\n" - }, - { - "task_id": "HumanEval/33", - "result": "def sort_third(l: list):\n sorted_third = sorted(l[i] for i in range(len(l)) if i % 3 == 0)\n \n result = l[:]\n j = 0\n for i in range(len(l)):\n if i % 3 == 0:\n result[i] = sorted_third[j]\n j += 1\n\n return result\n" - }, - { - "task_id": "HumanEval/34", - "result": "return sorted(set(l))\n" - }, - { - "task_id": "HumanEval/35", - "result": "def max_element(l: list):\n return max(l)\n" - }, - { - "task_id": "HumanEval/36", - "result": "count = 0\nfor i in range(n):\n if i % 11 == 0 or i % 13 == 0:\n count += str(i).count('7')\nreturn count\n" - }, - { - "task_id": "HumanEval/37", - "result": "def sort_even(l: list):\n even_indices = sorted(l[i] for i in range(0, len(l), 2))\n result = []\n even_index = 0\n for i in range(len(l)):\n if i % 2 == 0:\n result.append(even_indices[even_index])\n even_index += 1\n else:\n result.append(l[i])\n return result\n" - }, - { - "task_id": "HumanEval/38", - "result": "groups = [s[(3 * i):min((3 * i + 3), len(s))] for i in range((len(s) + 2) // 3)]\n groups = [(group[-1] + group[:-1]) if len(group) == 3 else group for group in groups]\n return \"\".join(groups)\n" - }, - { - "task_id": "HumanEval/39", - "result": "def is_prime(num):\n if num < 2:\n return False\n for i in range(2, int(num**0.5) + 1):\n if num % i == 0:\n return False\n return True\n\ndef prime_fib(n: int):\n fib1, fib2 = 0, 1\n prime_fib_count = 0\n current_prime_fib = None\n\n while prime_fib_count < n:\n fib1, fib2 = fib2, fib1 + fib2\n if is_prime(fib2):\n prime_fib_count += 1\n current_prime_fib = fib2\n\n return current_prime_fib\n" - }, - { - "task_id": "HumanEval/40", - "result": "def triples_sum_to_zero(l):\n n = len(l)\n for i in range(n):\n s = set()\n current_sum = -l[i]\n for j in range(i + 1, n):\n if (current_sum - l[j]) in s:\n return True\n s.add(l[j])\n return False\n" - }, - { - "task_id": "HumanEval/41", - "result": "def car_race_collision(n: int) -> int:\n return n * n\n" - }, - { - "task_id": "HumanEval/42", - "result": "def incr_list(l):\n return [x + 1 for x in l]\n" - }, - { - "task_id": "HumanEval/43", - "result": "def pairs_sum_to_zero(l):\n seen = set()\n for num in l:\n if -num in seen:\n return True\n seen.add(num)\n return False\n" - }, - { - "task_id": "HumanEval/44", - "result": "result = \"\"\n while x > 0:\n remainder = x % base\n result = str(remainder) + result # Prepend remainder to the result\n x //= base # Divide x by base\n return result if result else \"0\" # Handle case where x is 0\n" - }, - { - "task_id": "HumanEval/45", - "result": "def triangle_area(a, h):\n return 0.5 * a * h\n" - }, - { - "task_id": "HumanEval/46", - "result": "def fib4(n: int) -> int:\n if n == 0:\n return 0\n elif n == 1:\n return 0\n elif n == 2:\n return 2\n elif n == 3:\n return 0\n\n fib_sequence = [0, 0, 2, 0]\n for i in range(4, n + 1):\n next_value = fib_sequence[-1] + fib_sequence[-2] + fib_sequence[-3] + fib_sequence[-4]\n fib_sequence.append(next_value)\n\n return fib_sequence[n]\n" - }, - { - "task_id": "HumanEval/47", - "result": "l.sort()\n n = len(l)\n if n % 2 == 1: # odd length\n return l[n // 2]\n else: # even length\n return (l[n // 2 - 1] + l[n // 2]) / 2\n" - }, - { - "task_id": "HumanEval/48", - "result": "return text == text[::-1]\n" - }, - { - "task_id": "HumanEval/49", - "result": "return pow(2, n, p)\n" - }, - { - "task_id": "HumanEval/50", - "result": "def decode_shift(s: str):\n return \"\".join([chr(((ord(ch) - 5 - ord(\"a\")) % 26) + ord(\"a\")) for ch in s])\n" - }, - { - "task_id": "HumanEval/51", - "result": "def remove_vowels(text):\n vowels = \"aeiouAEIOU\"\n return ''.join([char for char in text if char not in vowels])\n" - }, - { - "task_id": "HumanEval/52", - "result": "for number in l:\n if number >= t:\n return False\nreturn True\n" - }, - { - "task_id": "HumanEval/53", - "result": "return x + y\n" - }, - { - "task_id": "HumanEval/54", - "result": "return set(s0) == set(s1)\n" - }, - { - "task_id": "HumanEval/55", - "result": "if n == 1 or n == 2:\n return 1\n a, b = 1, 1\n for _ in range(3, n + 1):\n a, b = b, a + b\n return b\n" - }, - { - "task_id": "HumanEval/56", - "result": "def correct_bracketing(brackets: str):\n count = 0\n for char in brackets:\n if char == \"<\":\n count += 1\n elif char == \">\":\n count -= 1\n if count < 0:\n return False\n return count == 0\n" - }, - { - "task_id": "HumanEval/57", - "result": "def monotonic(l: list):\n if len(l) <= 1:\n return True\n\n increasing = decreasing = True\n\n for i in range(1, len(l)):\n if l[i] > l[i - 1]:\n decreasing = False\n elif l[i] < l[i - 1]:\n increasing = False\n\n return increasing or decreasing\n" - }, - { - "task_id": "HumanEval/58", - "result": "def common(l1: list, l2: list):\n return sorted(set(l1) & set(l2))\n" - }, - { - "task_id": "HumanEval/59", - "result": "def largest_prime_factor(n):\n largest_factor = 1\n # Check for number of 2s that divide n\n while n % 2 == 0:\n largest_factor = 2\n n //= 2\n \n # n must be odd at this point, thus check for odd factors from 3\n for i in range(3, int(n**0.5) + 1, 2):\n while n % i == 0:\n largest_factor = i\n n //= i\n \n # This condition is to check if n is a prime number\n # greater than 2\n if n > 2:\n largest_factor = n\n \n return largest_factor\n" - }, - { - "task_id": "HumanEval/60", - "result": "def sum_to_n(n: int):\n return n * (n + 1) // 2\n" - }, - { - "task_id": "HumanEval/61", - "result": "def correct_bracketing(brackets: str) -> bool:\n counter = 0\n for char in brackets:\n if char == '(':\n counter += 1\n elif char == ')':\n counter -= 1\n if counter < 0:\n return False\n return counter == 0\n" - }, - { - "task_id": "HumanEval/62", - "result": "def derivative(xs):\n return [i * xs[i] for i in range(1, len(xs))]\n" - }, - { - "task_id": "HumanEval/63", - "result": "def fibfib(n: int, memo={0: 0, 1: 0, 2: 1}):\n if n in memo:\n return memo[n]\n memo[n] = fibfib(n-1, memo) + fibfib(n-2, memo) + fibfib(n-3, memo)\n return memo[n]\n" - }, - { - "task_id": "HumanEval/64", - "result": "def vowels_count(s):\n count = 0\n vowels = 'aeiou'\n \n for i, char in enumerate(s.lower()):\n if char in vowels or (char == 'y' and i == len(s) - 1):\n count += 1\n \n return count\n" - }, - { - "task_id": "HumanEval/65", - "result": "def circular_shift(x, shift):\n s = str(x)\n length = len(s)\n \n if shift > length:\n return s[::-1]\n \n shift = shift % length\n return s[-shift:] + s[:-shift]\n" - }, - { - "task_id": "HumanEval/66", - "result": "def digitSum(s):\n return sum(ord(char) for char in s if char.isupper())\n " - }, - { - "task_id": "HumanEval/67", - "result": "def fruit_distribution(s, n):\n apples = int(s.split()[0]) \n oranges = int(s.split()[3]) \n \n mangoes = n - apples - oranges\n return mangoes\n" - }, - { - "task_id": "HumanEval/68", - "result": "def pluck(arr):\n smallest_even = float('inf')\n smallest_index = -1\n \n for index, value in enumerate(arr):\n if value % 2 == 0: # Check if the value is even\n if value < smallest_even: # Check if it's the smallest even value\n smallest_even = value\n smallest_index = index\n\n if smallest_index == -1: # No even numbers found\n return []\n \n return [smallest_even, smallest_index]\n" - }, - { - "task_id": "HumanEval/69", - "result": "def search(lst):\n frequency = {}\n \n # Count frequency of each number\n for num in lst:\n if num in frequency:\n frequency[num] += 1\n else:\n frequency[num] = 1\n\n # Check for the greatest integer that meets the condition\n for num in sorted(frequency.keys(), reverse=True):\n if frequency[num] >= num:\n return num\n \n return -1\n" - }, - { - "task_id": "HumanEval/70", - "result": "def strange_sort_list(lst):\n lst.sort()\n result = []\n min_ptr, max_ptr = 0, len(lst) - 1\n \n while min_ptr <= max_ptr:\n if min_ptr == max_ptr:\n result.append(lst[min_ptr])\n else:\n result.append(lst[min_ptr])\n result.append(lst[max_ptr])\n \n min_ptr += 1\n max_ptr -= 1\n \n return result\n" - }, - { - "task_id": "HumanEval/71", - "result": "def triangle_area(a, b, c):\n if a + b > c and a + c > b and b + c > a: # Check validity\n s = (a + b + c) / 2 # Semi-perimeter\n area = (s * (s - a) * (s - b) * (s - c)) ** 0.5 # Heron's formula\n return round(area, 2) # Return area rounded to 2 decimal points\n return -1 # Not a valid triangle\n" - }, - { - "task_id": "HumanEval/72", - "result": "def will_it_fly(q, w):\n return q == q[::-1] and sum(q) <= w\n" - }, - { - "task_id": "HumanEval/73", - "result": "def smallest_change(arr):\n changes = 0\n n = len(arr)\n \n for i in range(n // 2):\n if arr[i] != arr[n - 1 - i]:\n changes += 1\n \n return changes\n" - }, - { - "task_id": "HumanEval/74", - "result": "def total_match(lst1, lst2):\n total_chars_lst1 = sum(len(s) for s in lst1)\n total_chars_lst2 = sum(len(s) for s in lst2)\n\n if total_chars_lst1 < total_chars_lst2:\n return lst1\n elif total_chars_lst1 > total_chars_lst2:\n return lst2\n else:\n return lst1\n" - }, - { - "task_id": "HumanEval/75", - "result": "def is_multiply_prime(a):\n primes = [prime(i) for i in range(1, 30) if prime(i) < 100]\n for combo in combinations(primes, 3):\n if combo[0] * combo[1] * combo[2] == a:\n return True\n return False\n" - }, - { - "task_id": "HumanEval/76", - "result": "def is_simple_power(x, n):\n if n <= 1:\n return x == n\n power = 1\n while power < x:\n power *= n\n return power == x\n" - }, - { - "task_id": "HumanEval/77", - "result": "return round(abs(a) ** (1/3)) ** 3 == abs(a)\n" - }, - { - "task_id": "HumanEval/78", - "result": "prime_hex_digits = {'2', '3', '5', '7', 'B', 'D'}\ncount = 0\n\nfor digit in num:\n if digit in prime_hex_digits:\n count += 1\n\nreturn count\n" - }, - { - "task_id": "HumanEval/79", - "result": "def decimal_to_binary(decimal):\n return 'db' + bin(decimal)[2:] + 'db'\n" - }, - { - "task_id": "HumanEval/80", - "result": "def is_happy(s):\n if len(s) < 3:\n return False\n for i in range(len(s) - 2):\n if len(set(s[i:i + 3])) < 3:\n return False\n return True\n" - }, - { - "task_id": "HumanEval/81", - "result": "def numerical_letter_grade(grades):\n letter_grades = []\n for gpa in grades:\n if gpa == 4.0:\n letter_grades.append('A+')\n elif gpa > 3.7:\n letter_grades.append('A')\n elif gpa > 3.3:\n letter_grades.append('A-')\n elif gpa > 3.0:\n letter_grades.append('B+')\n elif gpa > 2.7:\n letter_grades.append('B')\n elif gpa > 2.3:\n letter_grades.append('B-')\n elif gpa > 2.0:\n letter_grades.append('C+')\n elif gpa > 1.7:\n letter_grades.append('C')\n elif gpa > 1.3:\n letter_grades.append('C-')\n elif gpa > 1.0:\n letter_grades.append('D+')\n elif gpa > 0.7:\n letter_grades.append('D')\n elif gpa > 0.0:\n letter_grades.append('D-')\n else:\n letter_grades.append('E')\n return letter_grades\n" - }, - { - "task_id": "HumanEval/82", - "result": "def prime_length(string):\n def is_prime(n):\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n \n length = len(string)\n return is_prime(length)\n" - }, - { - "task_id": "HumanEval/83", - "result": "def starts_one_ends(n):\n if n <= 0:\n return 0\n # Numbers starting with 1\n start_with_1 = 10**(n-1) # 1 followed by (n-1) zeros\n # Numbers ending with 1\n end_with_1 = 10**(n-1)\n\n # Counting overlaps (i.e., numbers that both start and end with 1)\n # These are of the form 1...1, and there are (n-2) digits in between\n overlap_count = 10**(n-2) if n > 1 else 1\n\n return start_with_1 + end_with_1 - overlap_count\n " - }, - { - "task_id": "HumanEval/84", - "result": "def solve(N):\n if not (0 <= N <= 10000):\n raise ValueError(\"N must be between 0 and 10000\")\n\n digit_sum = sum(int(digit) for digit in str(N))\n return bin(digit_sum)[2:]\n" - }, - { - "task_id": "HumanEval/85", - "result": "def add(lst):\n total = 0\n for index, value in enumerate(lst):\n if index % 2 != 0 and value % 2 == 0:\n total += value\n return total\n" - }, - { - "task_id": "HumanEval/86", - "result": "def anti_shuffle(s):\n result = []\n for word in s.split(' '):\n sorted_word = ''.join(sorted(word))\n result.append(sorted_word)\n return ' '.join(result)\n" - }, - { - "task_id": "HumanEval/87", - "result": "coordinates = []\n\nfor row_index, row in enumerate(lst):\n for col_index, value in enumerate(row):\n if value == x:\n coordinates.append((row_index, col_index))\n\ncoordinates.sort(key=lambda coord: (coord[0], -coord[1]))\n\nreturn coordinates\n" - }, - { - "task_id": "HumanEval/88", - "result": "def sort_array(array):\n sum_first_last = array[0] + array[-1] if array else 0\n return sorted(array) if sum_first_last % 2 != 0 else sorted(array, reverse=True)\n" - }, - { - "task_id": "HumanEval/89", - "result": "def encrypt(s):\n result = \"\"\n for char in s:\n if 'a' <= char <= 'z': # Check if char is a lowercase letter\n new_char = chr((ord(char) - ord('a') + 4) % 26 + ord('a'))\n result += new_char\n return result\n" - }, - { - "task_id": "HumanEval/90", - "result": "def next_smallest(lst):\n if not lst:\n return None\n unique_elements = list(set(lst))\n unique_elements.sort()\n if len(unique_elements) < 2:\n return None\n return unique_elements[1]\n" - }, - { - "task_id": "HumanEval/91", - "result": "sentences = [s.strip() for s in re.split(r'[.!?]', S) if s] # Split into sentences\nreturn sum(1 for sentence in sentences if sentence.startswith(\"I\")) # Count \"I\"-starting sentences\n" - }, - { - "task_id": "HumanEval/92", - "result": "def any_int(x, y, z):\n return all(isinstance(i, int) for i in (x, y, z)) and (\n x == y + z or y == x + z or z == x + y\n )\n" - }, - { - "task_id": "HumanEval/93", - "result": "def encode(message):\n vowels = {'a': 'c', 'e': 'g', 'i': 'k', 'o': 'q', 'u': 'w',\n 'A': 'C', 'E': 'G', 'I': 'K', 'O': 'Q', 'U': 'W'}\n \n result = []\n for char in message:\n if char in vowels:\n result.append(vowels[char])\n elif char.isalpha():\n result.append(char.swapcase())\n else:\n result.append(char)\n \n return ''.join(result)\n" - }, - { - "task_id": "HumanEval/94", - "result": "def skjkasdkd(lst):\n def is_prime(n):\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n \n largest_prime = None\n \n for num in lst:\n if is_prime(num):\n if largest_prime is None or num > largest_prime:\n largest_prime = num\n \n if largest_prime is None:\n return 0 # or some other default value if there's no prime\n \n return sum(int(digit) for digit in str(largest_prime))\n" - }, - { - "task_id": "HumanEval/95", - "result": "def check_dict_case(d):\n if not d: # Check if the dictionary is empty\n return False\n \n keys = d.keys() # Get all keys from the dictionary\n all_lower = all(isinstance(k, str) and k.islower() for k in keys) # Check if all keys are lower case\n all_upper = all(isinstance(k, str) and k.isupper() for k in keys) # Check if all keys are upper case\n \n return all_lower or all_upper # Return True if either condition is met\n" - }, - { - "task_id": "HumanEval/96", - "result": "def is_prime(num):\n if num < 2:\n return False\n for i in range(2, int(num**0.5) + 1):\n if num % i == 0:\n return False\n return True\n\ndef count_up_to(n):\n return [i for i in range(2, n) if is_prime(i)]\n" - }, - { - "task_id": "HumanEval/97", - "result": "def multiply(a, b):\n # Get the unit digit of each number\n unit_digit_a = abs(a) % 10\n unit_digit_b = abs(b) % 10\n # Return the product of the unit digits\n return unit_digit_a * unit_digit_b\n " - }, - { - "task_id": "HumanEval/98", - "result": "def count_upper(s):\n count = 0\n for i in range(0, len(s), 2):\n if s[i] in 'AEIOU':\n count += 1\n return count\n " - }, - { - "task_id": "HumanEval/99", - "result": "number = float(value)\n floor_value = int(number) # Get the floor value of the number\n ceil_value = floor_value + 1 # Get the ceiling value\n \n if number - floor_value < 0.5:\n return floor_value\n elif number - floor_value > 0.5:\n return ceil_value\n else: # number - floor_value == 0.5\n return ceil_value if number > 0 else floor_value\n" - }, - { - "task_id": "HumanEval/100", - "result": "def make_a_pile(n):\n stones = []\n current_stones = n\n \n for i in range(n):\n stones.append(current_stones)\n if current_stones % 2 == 0: # current_stones is even\n current_stones += 2 # next level will have the next even number\n else:\n current_stones += 2 # next level will have the next odd number\n \n return stones\n" - }, - { - "task_id": "HumanEval/101", - "result": "import re\n\ndef words_string(s):\n return re.split(r'[ ,]+', s)\n" - }, - { - "task_id": "HumanEval/102", - "result": "def choose_num(x, y):\n lower = min(x, y)\n upper = max(x, y)\n \n for num in range(upper, lower - 1, -1):\n if num % 2 == 0:\n return num\n return -1\n" - }, - { - "task_id": "HumanEval/103", - "result": "def rounded_avg(n, m):\n if n > m:\n return -1\n avg = round((n + m) / 2)\n return bin(avg)\n" - }, - { - "task_id": "HumanEval/104", - "result": "result = []\nfor num in x:\n if all(int(digit) % 2 != 0 for digit in str(num)): # Check if all digits are odd\n result.append(num)\nreturn sorted(result)\n" - }, - { - "task_id": "HumanEval/105", - "result": "def by_length(arr):\n filtered = [x for x in arr if 1 <= x <= 9] # Step 1: Filter numbers\n sorted_arr = sorted(filtered) # Step 2: Sort the array\n reversed_arr = sorted_arr[::-1] # Step 3: Reverse the array\n\n # Step 4: Map integers to their names\n number_names = [\"One\", \"Two\", \"Three\", \"Four\", \"Five\", \"Six\", \"Seven\", \"Eight\", \"Nine\"]\n result = [number_names[x - 1] for x in reversed_arr] # Step 5: Replace with names\n return result\n" - }, - { - "task_id": "HumanEval/106", - "result": "result = []\nfor i in range(1, n + 1):\n if i % 2 == 0: # i is even\n factorial = 1\n for j in range(1, i + 1):\n factorial *= j\n result.append(factorial)\n else: # i is odd\n sum_odd = sum(range(1, i + 1))\n result.append(sum_odd)\nreturn result\n" - }, - { - "task_id": "HumanEval/107", - "result": "def even_odd_palindrome(n):\n def is_palindrome(num):\n return str(num) == str(num)[::-1]\n \n odd_count = 0\n even_count = 0\n \n for i in range(1, n + 1):\n if is_palindrome(i):\n if i % 2 == 0:\n even_count += 1\n else:\n odd_count += 1\n \n return (even_count, odd_count)\n" - }, - { - "task_id": "HumanEval/108", - "result": "def count_nums(arr):\n count = 0\n for num in arr:\n digit_sum = sum(int(digit) if num >= 0 else -int(digit) for digit in str(abs(num)))\n if digit_sum > 0:\n count += 1\n return count\n" - }, - { - "task_id": "HumanEval/109", - "result": "def move_one_ball(arr):\n if not arr:\n return True\n\n descents = 0\n n = len(arr)\n\n for i in range(n):\n if arr[i] > arr[(i + 1) % n]: # Use modulo to wrap around\n descents += 1\n\n return descents <= 1\n" - }, - { - "task_id": "HumanEval/110", - "result": "def exchange(lst1, lst2):\n odd_count = sum(1 for x in lst1 if x % 2 != 0)\n even_count_in_lst2 = sum(1 for x in lst2 if x % 2 == 0)\n if odd_count <= even_count_in_lst2:\n return \"YES\"\n else:\n return \"NO\"\n" - }, - { - "task_id": "HumanEval/111", - "result": "def histogram(test):\n counts = {}\n \n # Split the input string into letters and count occurrences\n for letter in test.split():\n counts[letter] = counts.get(letter, 0) + 1\n \n if not counts:\n return {}\n \n # Find the maximum count\n max_count = max(counts.values())\n \n # Gather all letters with the maximum count\n result = {letter: count for letter, count in counts.items() if count == max_count}\n \n return result\n" - }, - { - "task_id": "HumanEval/112", - "result": "def reverse_delete(s, c):\n result = ''.join(char for char in s if char not in c) # Step 1: Remove characters\n is_palindrome = result == result[::-1] # Step 2: Check for palindrome\n return result, is_palindrome # Step 3: Return result\n" - }, - { - "task_id": "HumanEval/113", - "result": "def odd_count(lst):\n result = []\n for s in lst:\n odd_count = sum(1 for char in s if char in '13579')\n result.append(f\"the number of odd elements {odd_count}n the str{odd_count}ng {odd_count} of the {odd_count}nput.\")\n return result\n" - }, - { - "task_id": "HumanEval/114", - "result": "def minSubArraySum(nums):\n min_sum = float('inf')\n current_sum = 0\n\n for num in nums:\n current_sum += num\n if current_sum < min_sum:\n min_sum = current_sum\n if current_sum > 0:\n current_sum = 0\n\n return min_sum\n" - }, - { - "task_id": "HumanEval/115", - "result": "def max_fill(grid, capacity):\n total_water = 0\n \n # Count total water in the grid\n for row in grid:\n total_water += sum(row)\n \n # Calculate number of times to lower buckets\n return math.ceil(total_water / capacity)\n" - }, - { - "task_id": "HumanEval/116", - "result": "def sort_array(arr):\n arr.sort(key=lambda x: (bin(x).count('1'), x))\n return arr\n" - }, - { - "task_id": "HumanEval/117", - "result": "def select_words(s, n):\n if not s:\n return []\n \n def count_consonants(word):\n consonants = \"bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ\"\n return sum(1 for char in word if char in consonants)\n \n words = s.split()\n result = [word for word in words if count_consonants(word) == n]\n \n return result\n" - }, - { - "task_id": "HumanEval/118", - "result": "def get_closest_vowel(word):\n vowels = 'aeiouAEIOU'\n last_consonants = []\n \n # Traverse the string from right to left\n for char in reversed(word):\n if char in vowels:\n # Check for vowels between two consonants\n if len(last_consonants) == 2:\n return char\n elif char.isalpha(): # It is a consonant\n last_consonants.append(char)\n # Keep only the last two consonants\n if len(last_consonants) > 2:\n last_consonants.pop(0)\n\n return \"\"\n" - }, - { - "task_id": "HumanEval/119", - "result": "def match_parens(lst):\n s1, s2 = lst\n\n def is_balanced(s1, s2):\n count = 0\n for char in s1 + s2:\n if char == '(':\n count += 1\n else:\n count -= 1\n if count < 0:\n return False\n return count == 0\n\n return 'Yes' if is_balanced(s1, s2) or is_balanced(s2, s1) else 'No'\n" - }, - { - "task_id": "HumanEval/120", - "result": "def maximum(arr, k):\n return sorted(sorted(arr)[-k:])\n" - }, - { - "task_id": "HumanEval/121", - "result": "total_sum = sum(lst[i] for i in range(len(lst)) if i % 2 == 0 and lst[i] % 2 != 0)\nreturn total_sum\n" - }, - { - "task_id": "HumanEval/122", - "result": "def add_elements(arr, k):\n return sum(x for x in arr[:k] if -10 < x < 100)\n " - }, - { - "task_id": "HumanEval/123", - "result": "def get_odd_collatz(n):\n odd_numbers = []\n \n while n != 1:\n if n % 2 != 0: # n is odd\n odd_numbers.append(n)\n n = n // 2 if n % 2 == 0 else 3 * n + 1\n \n odd_numbers.append(1) # Append 1 as it's also considered odd\n return sorted(odd_numbers)\n" - }, - { - "task_id": "HumanEval/124", - "result": "def valid_date(date):\n if not date:\n return False\n \n if date.count('-') != 2:\n return False\n \n month, day, year = date.split('-')\n \n try:\n month = int(month)\n day = int(day)\n year = int(year)\n except ValueError:\n return False\n \n if month < 1 or month > 12:\n return False\n \n if month in [1, 3, 5, 7, 8, 10, 12]:\n if day < 1 or day > 31:\n return False\n elif month in [4, 6, 9, 11]:\n if day < 1 or day > 30:\n return False\n elif month == 2:\n if day < 1 or day > 29:\n return False\n \n return True\n" - }, - { - "task_id": "HumanEval/125", - "result": "def split_words(txt):\n if any(char.isspace() for char in txt):\n return txt.split()\n elif ',' in txt:\n return txt.split(',')\n else:\n return sum(1 for char in txt if char.islower() and (ord(char) - ord('a')) % 2 == 0)\n" - }, - { - "task_id": "HumanEval/126", - "result": "def is_sorted(lst):\n return lst == sorted(lst) and len(lst) == len(set(lst))\n" - }, - { - "task_id": "HumanEval/127", - "result": "def intersection(interval1, interval2):\n start1, end1 = interval1\n start2, end2 = interval2\n\n # Calculate the intersection\n start_intersection = max(start1, start2)\n end_intersection = min(end1, end2)\n\n # Check if there is an intersection\n if start_intersection >= end_intersection:\n return \"NO\"\n\n # Calculate length of the intersection\n length = end_intersection - start_intersection\n\n # Function to check if a number is prime\n def is_prime(n):\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n\n # Check if the length of the intersection is prime\n if is_prime(length):\n return \"YES\"\n else:\n return \"NO\"\n" - }, - { - "task_id": "HumanEval/128", - "result": "def prod_signs(arr):\n if not arr:\n return None\n \n product_of_signs = 1\n sum_of_magnitudes = 0\n \n for num in arr:\n if num > 0:\n sum_of_magnitudes += num\n elif num < 0:\n sum_of_magnitudes += -num\n product_of_signs *= -1\n else: # num == 0\n product_of_signs = 0\n \n return sum_of_magnitudes * product_of_signs\n" - }, - { - "task_id": "HumanEval/129", - "result": "def minPath(grid, k):\n from itertools import product\n \n n = len(grid)\n best_path = []\n\n def dfs(r, c, path):\n nonlocal best_path\n \n if len(path) == k:\n if not best_path or path < best_path:\n best_path = path[:]\n return\n \n directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]\n for dr, dc in directions:\n nr, nc = r + dr, c + dc\n if 0 <= nr < n and 0 <= nc < n:\n path.append(grid[nr][nc])\n dfs(nr, nc, path)\n path.pop()\n\n for i, j in product(range(n), repeat=2):\n dfs(i, j, [grid[i][j]])\n\n return best_path\n" - }, - { - "task_id": "HumanEval/130", - "result": "def tri(n):\n tribonacci = []\n \n for i in range(n + 1):\n if i == 0:\n tribonacci.append(1)\n elif i == 1:\n tribonacci.append(3)\n elif i % 2 == 0: # Even\n tribonacci.append(1 + i / 2)\n else: # Odd\n tribonacci.append(\n tribonacci[i - 1] + tribonacci[i - 2] + tribonacci[i + 1] if (i + 1 <= n) else tribonacci[i - 1] + tribonacci[i - 2]\n )\n \n return tribonacci\n" - }, - { - "task_id": "HumanEval/131", - "result": "def digits(n):\n product = 1\n has_odd = False\n while n > 0:\n digit = n % 10\n if digit % 2 != 0: # Check if the digit is odd\n product *= digit\n has_odd = True\n n //= 10 # Remove the last digit\n return product if has_odd else 0\n " - }, - { - "task_id": "HumanEval/132", - "result": "def is_nested(string):\n stack = []\n nested = False\n\n for char in string:\n if char == '[':\n stack.append(char)\n elif char == ']':\n if stack:\n top = stack.pop()\n if stack: # Check if there are still brackets in the stack\n nested = True # We found a nested bracket\n else:\n return False # More closing brackets than opening\n\n # If there are still items in stack, that means we have unmatched opening brackets\n return nested\n\n# Example tests\nprint(is_nested('[[]]')) # ➞ True\nprint(is_nested('[]]]]]]][[[[[]')) # ➞ False\nprint(is_nested('[][]')) # ➞ False\nprint(is_nested('[]')) # ➞ False\nprint(is_nested('[[][]]')) # ➞ True\nprint(is_nested('[[]][[')) # ➞ True\n" - }, - { - "task_id": "HumanEval/133", - "result": "import math\n\ndef sum_squares(lst):\n return sum(math.ceil(x) ** 2 for x in lst)\n" - }, - { - "task_id": "HumanEval/134", - "result": "def check_if_last_char_is_a_letter(txt):\n txt = txt.rstrip() # Remove trailing spaces\n if len(txt) == 0: # Check if the string is empty\n return False\n last_char = txt[-1] # Get the last character\n\n # Check if last_char is a letter and is not part of a word\n return last_char.isalpha() and (len(txt) == 1 or txt[-2] == ' ')\n" - }, - { - "task_id": "HumanEval/135", - "result": "for i in range(1, len(arr)):\n if arr[i] < arr[i - 1]:\n return i\n return -1\n" - }, - { - "task_id": "HumanEval/136", - "result": "largest_smallest_integers(lst):\n largest_negative = None\n smallest_positive = None\n \n for number in lst:\n if number < 0:\n if largest_negative is None or number > largest_negative:\n largest_negative = number\n elif number > 0:\n if smallest_positive is None or number < smallest_positive:\n smallest_positive = number\n\n return (largest_negative, smallest_positive)\n" - }, - { - "task_id": "HumanEval/137", - "result": "def compare_one(a, b):\n def to_float(value):\n if isinstance(value, str):\n value = value.replace(',', '.') \n return float(value)\n\n try:\n float_a = to_float(a)\n float_b = to_float(b)\n except ValueError:\n return None\n\n if float_a > float_b:\n return a\n elif float_a < float_b:\n return b\n else:\n return None\n" - }, - { - "task_id": "HumanEval/138", - "result": "def is_equal_to_sum_even(n):\n return n >= 8 and n % 2 == 0\n" - }, - { - "task_id": "HumanEval/139", - "result": "def special_factorial(n):\n def factorial(x):\n if x == 0 or x == 1:\n return 1\n else:\n result = 1\n for i in range(2, x + 1):\n result *= i\n return result\n\n result = 1\n for i in range(1, n + 1):\n result *= factorial(i)\n \n return result\n" - }, - { - "task_id": "HumanEval/140", - "result": "def fix_spaces(text):\n import re\n text = text.lstrip(' ')\n text = re.sub(r' {2,}', '-', text)\n text = text.replace(' ', '_')\n if text.startswith('_'):\n text = '_' + text.strip('_')\n return text\n" - }, - { - "task_id": "HumanEval/141", - "result": "def file_name_check(file_name):\n # Check for one dot\n if file_name.count('.') != 1:\n return 'No'\n \n # Split the name into the part before and after the dot\n name_part, ext_part = file_name.split('.')\n \n # Check if the name part is empty and starts with a letter\n if not name_part or not name_part[0].isalpha():\n return 'No'\n \n # Check for valid file extensions\n valid_extensions = ['txt', 'exe', 'dll']\n if ext_part not in valid_extensions:\n return 'No'\n \n # Count the digits in the file name\n digit_count = sum(c.isdigit() for c in file_name)\n if digit_count > 3:\n return 'No'\n \n return 'Yes'\n" - }, - { - "task_id": "HumanEval/142", - "result": "def sum_squares(lst):\n total_sum = 0\n for index, value in enumerate(lst):\n if index % 3 == 0:\n total_sum += value ** 2\n elif index % 4 == 0:\n total_sum += value ** 3\n else:\n total_sum += value\n return total_sum\n" - }, - { - "task_id": "HumanEval/143", - "result": "def words_in_sentence(sentence):\n def is_prime(n):\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n\n words = sentence.split()\n prime_length_words = [word for word in words if is_prime(len(word))]\n return ' '.join(prime_length_words)\n" - }, - { - "task_id": "HumanEval/144", - "result": "def simplify(x, n):\n num1, denom1 = map(int, x.split('/'))\n num2, denom2 = map(int, n.split('/'))\n \n result_numerator = num1 * num2\n result_denominator = denom1 * denom2\n \n return result_numerator % result_denominator == 0\n" - }, - { - "task_id": "HumanEval/145", - "result": "def order_by_points(nums):\n def sum_of_digits(n):\n return sum(int(digit) for digit in str(abs(n)))\n\n return sorted(nums, key=lambda x: (sum_of_digits(x), nums.index(x)))\n" - }, - { - "task_id": "HumanEval/146", - "result": "def specialFilter(nums):\n count = 0\n for num in nums:\n if num > 10:\n num_str = str(num)\n first_digit = int(num_str[0])\n last_digit = int(num_str[-1])\n if first_digit % 2 != 0 and last_digit % 2 != 0:\n count += 1\n return count\n" - }, - { - "task_id": "HumanEval/147", - "result": "a = [i * i - i + 1 for i in range(1, n + 1)]\ncount = 0\n\n# Iterate through all possible triples\nfor i in range(n):\n for j in range(i + 1, n):\n for k in range(j + 1, n):\n if (a[i] + a[j] + a[k]) % 3 == 0:\n count += 1\n \nreturn count\n" - }, - { - "task_id": "HumanEval/148", - "result": "def bf(planet1, planet2):\n planets = [\"Mercury\", \"Venus\", \"Earth\", \"Mars\", \"Jupiter\", \"Saturn\", \"Uranus\", \"Neptune\"]\n if planet1 not in planets or planet2 not in planets:\n return ()\n \n index1 = planets.index(planet1)\n index2 = planets.index(planet2)\n \n if index1 > index2:\n index1, index2 = index2, index1\n \n return tuple(planets[index1 + 1:index2])\n" - }, - { - "task_id": "HumanEval/149", - "result": "def sorted_list_sum(lst):\n # Remove strings with odd lengths\n filtered = [s for s in lst if len(s) % 2 == 0]\n # Sort by length and then alphabetically\n sorted_list = sorted(filtered, key=lambda x: (len(x), x))\n return sorted_list\n" - }, - { - "task_id": "HumanEval/150", - "result": "def x_or_y(n, x, y):\n def is_prime(num):\n if num <= 1:\n return False\n for i in range(2, int(num**0.5) + 1):\n if num % i == 0:\n return False\n return True\n \n return x if is_prime(n) else y\n" - }, - { - "task_id": "HumanEval/151", - "result": "def double_the_difference(lst):\n odd_squares_sum = sum(x ** 2 for x in lst if x >= 0 and x % 2 == 1)\n return odd_squares_sum\n" - }, - { - "task_id": "HumanEval/152", - "result": "def compare(game, guess):\n return [abs(g - s) for g, s in zip(guess, game)]\n" - }, - { - "task_id": "HumanEval/153", - "result": "def Strongest_Extension(class_name, extensions):\n strongest_extension = \"\"\n max_strength = float('-inf') # Initialize to negative infinity to find the max\n\n for extension in extensions:\n CAP = sum(1 for char in extension if char.isupper())\n SM = sum(1 for char in extension if char.islower())\n strength = CAP - SM\n \n if strength > max_strength: # Update if this extension is stronger\n max_strength = strength\n strongest_extension = extension\n\n return f\"{class_name}.{strongest_extension}\"\n" - }, - { - "task_id": "HumanEval/154", - "result": "def cycpattern_check(a, b):\n if len(b) == 0:\n return True\n return any(b[i:i+len(b)] in a for i in range(len(b)))\n" - }, - { - "task_id": "HumanEval/155", - "result": "even_count = 0\n odd_count = 0\n\n for digit in str(abs(num)):\n if int(digit) % 2 == 0:\n even_count += 1\n else:\n odd_count += 1\n\n return (even_count, odd_count)\n" - }, - { - "task_id": "HumanEval/156", - "result": "def int_to_mini_roman(number):\n roman_numerals = [\n (1000, 'm'), (900, 'cm'), (500, 'd'), (400, 'cd'),\n (100, 'c'), (90, 'xc'), (50, 'l'), (40, 'xl'),\n (10, 'x'), (9, 'ix'), (5, 'v'), (4, 'iv'), (1, 'i')\n ]\n \n result = \"\"\n \n for value, numeral in roman_numerals:\n while number >= value:\n result += numeral\n number -= value\n \n return result\n" - }, - { - "task_id": "HumanEval/157", - "result": "sides = sorted([a, b, c])\nreturn sides[0]**2 + sides[1]**2 == sides[2]**2\n" - }, - { - "task_id": "HumanEval/158", - "result": "def find_max(words):\n max_word = \"\"\n max_unique_count = 0\n \n for word in words:\n unique_chars = len(set(word))\n \n if (unique_chars > max_unique_count or \n (unique_chars == max_unique_count and word < max_word)):\n max_word = word\n max_unique_count = unique_chars\n \n return max_word\n" - }, - { - "task_id": "HumanEval/159", - "result": "def eat(number, need, remaining):\n total_eaten = number\n if need <= remaining:\n total_eaten += need\n remaining -= need\n else:\n total_eaten += remaining\n remaining = 0\n return [total_eaten, remaining]\n" - }, - { - "task_id": "HumanEval/160", - "result": "def do_algebra(operator, operand):\n result = operand[0]\n for i in range(len(operator)):\n if operator[i] == '+':\n result += operand[i + 1]\n elif operator[i] == '-':\n result -= operand[i + 1]\n elif operator[i] == '*':\n result *= operand[i + 1]\n elif operator[i] == '//':\n result //= operand[i + 1]\n elif operator[i] == '**':\n result **= operand[i + 1]\n return result\n" - }, - { - "task_id": "HumanEval/161", - "result": "def solve(s):\n # Check if there are any letters in the input string\n has_letter = any(c.isalpha() for c in s)\n\n if not has_letter:\n # Reverse the string if no letters are present\n return s[::-1]\n else:\n # Create a list to hold the new characters\n result = []\n # Iterate through each character in the string\n for c in s:\n if c.isalpha():\n # Reverse case for letters\n if c.islower():\n result.append(c.upper())\n else:\n result.append(c.lower())\n else:\n # Keep non-letter characters as they are\n result.append(c)\n return ''.join(result)\n " - }, - { - "task_id": "HumanEval/162", - "result": "import hashlib\n\ndef string_to_md5(text):\n if text == \"\":\n return None\n hash_object = hashlib.md5(text.encode())\n return hash_object.hexdigest()\n" - }, - { - "task_id": "HumanEval/163", - "result": "def generate_integers(a, b):\n lower = min(a, b)\n upper = max(a, b)\n return [n for n in range(lower, upper + 1) if n % 2 == 0]\n" - } -] \ No newline at end of file diff --git a/experiment/humaneval/interpreter_prediction.jsonl b/experiment/humaneval/interpreter_prediction.jsonl index c7ba7a0c0..06b04e57b 100644 --- a/experiment/humaneval/interpreter_prediction.jsonl +++ b/experiment/humaneval/interpreter_prediction.jsonl @@ -1,164 +1,164 @@ -{"task_id": "HumanEval/0", "completion": "for i in range(len(numbers)):\n for j in range(i + 1, len(numbers)):\n if abs(numbers[i] - numbers[j]) < threshold:\n return True\n return False\n"} -{"task_id": "HumanEval/1", "completion": "def separate_paren_groups(paren_string: str) -> List[str]:\n paren_string = paren_string.replace(\" \", \"\") # Step 1: Remove spaces\n result = []\n stack = []\n current_group = []\n\n for char in paren_string:\n if char == '(':\n if not stack: # Starting a new group\n current_group = [] # Reset current group\n stack.append(char)\n current_group.append(char) # Add to current group\n elif char == ')':\n stack.pop()\n current_group.append(char) # Add to current group\n if not stack: # If stack is empty, a complete group is found\n result.append(''.join(current_group)) # Add to result\n\n return result\n"} -{"task_id": "HumanEval/2", "completion": "def truncate_number(number: float) -> float:\n return number - int(number)\n"} -{"task_id": "HumanEval/3", "completion": "def below_zero(operations: List[int]) -> bool:\n balance = 0\n for operation in operations:\n balance += operation\n if balance < 0:\n return True\n return False\n"} -{"task_id": "HumanEval/4", "completion": "mean_value = sum(numbers) / len(numbers) # Calculate mean\ndeviations = [abs(x - mean_value) for x in numbers] # Calculate absolute differences\nreturn sum(deviations) / len(deviations) # Calculate and return MAD\n"} -{"task_id": "HumanEval/5", "completion": "def intersperse(numbers: List[int], delimeter: int) -> List[int]:\n if not numbers:\n return []\n \n result = []\n for i in range(len(numbers)):\n result.append(numbers[i])\n if i < len(numbers) - 1: # Don't add delimeter after the last element\n result.append(delimeter)\n \n return result\n"} -{"task_id": "HumanEval/6", "completion": "def parse_nested_parens(paren_string: str) -> List[int]:\n depths = []\n groups = paren_string.split()\n\n for group in groups:\n max_depth = 0\n current_depth = 0\n \n for char in group:\n if char == '(':\n current_depth += 1\n max_depth = max(max_depth, current_depth)\n elif char == ')':\n current_depth -= 1\n \n depths.append(max_depth)\n\n return depths\n"} -{"task_id": "HumanEval/7", "completion": "return [s for s in strings if substring in s]\n"} -{"task_id": "HumanEval/8", "completion": "def sum_product(numbers: List[int]) -> Tuple[int, int]:\n total_sum = sum(numbers)\n total_product = 1\n for number in numbers:\n total_product *= number\n return total_sum, total_product\n"} -{"task_id": "HumanEval/9", "completion": "def rolling_max(numbers: List[int]) -> List[int]:\n max_so_far = float('-inf')\n rolling_max_list = []\n\n for number in numbers:\n if number > max_so_far:\n max_so_far = number\n rolling_max_list.append(max_so_far)\n\n return rolling_max_list\n"} -{"task_id": "HumanEval/10", "completion": "def make_palindrome(string: str) -> str:\n def is_palindrome(s: str) -> bool:\n return s == s[::-1]\n\n for i in range(len(string)):\n if is_palindrome(string[i:]):\n return string + string[:i][::-1]\n \n return string\n"} -{"task_id": "HumanEval/11", "completion": "result = ''.join(str(int(x) ^ int(y)) for x, y in zip(a, b))\n"} -{"task_id": "HumanEval/12", "completion": "def longest(strings: List[str]) -> Optional[str]:\n if not strings:\n return None\n longest_string = \"\"\n for string in strings:\n if len(string) > len(longest_string):\n longest_string = string\n return longest_string\n"} -{"task_id": "HumanEval/13", "completion": "def greatest_common_divisor(a: int, b: int) -> int:\n while b:\n a, b = b, a % b\n return a\n"} -{"task_id": "HumanEval/14", "completion": "return [string[:i] for i in range(1, len(string) + 1)]\n"} -{"task_id": "HumanEval/15", "completion": "return ' '.join(str(i) for i in range(n + 1))\n"} -{"task_id": "HumanEval/16", "completion": "return len(set(string.lower()))\n"} -{"task_id": "HumanEval/17", "completion": "def parse_music(music_string: str) -> List[int]:\n note_duration_map = {\n 'o': 4,\n 'o|': 2,\n '.|': 1\n }\n \n notes = music_string.split()\n durations = [note_duration_map[note] for note in notes]\n \n return durations\n"} -{"task_id": "HumanEval/18", "completion": "def how_many_times(string: str, substring: str) -> int:\n count = 0\n start = 0\n\n while True:\n start = string.find(substring, start)\n if start == -1:\n break\n count += 1\n start += 1 # Move to the next character to allow for overlapping\n\n return count\n"} -{"task_id": "HumanEval/19", "completion": "def sort_numbers(numbers: str) -> str:\n number_map = {\n 'zero': 0,\n 'one': 1,\n 'two': 2,\n 'three': 3,\n 'four': 4,\n 'five': 5,\n 'six': 6,\n 'seven': 7,\n 'eight': 8,\n 'nine': 9\n }\n \n words = numbers.split()\n sorted_numbers = sorted(words, key=lambda x: number_map[x])\n return ' '.join(sorted_numbers)\n"} -{"task_id": "HumanEval/20", "completion": "def find_closest_elements(numbers: List[float]) -> Tuple[float, float]:\n numbers.sort()\n closest_pair = (numbers[0], numbers[1])\n min_diff = abs(numbers[1] - numbers[0])\n \n for i in range(1, len(numbers) - 1):\n diff = abs(numbers[i + 1] - numbers[i])\n if diff < min_diff:\n min_diff = diff\n closest_pair = (numbers[i], numbers[i + 1])\n \n return closest_pair\n"} -{"task_id": "HumanEval/21", "completion": "return [(num - min_val) / (max_val - min_val) for num in numbers]\n"} -{"task_id": "HumanEval/22", "completion": "return [value for value in values if isinstance(value, int)]\n"} -{"task_id": "HumanEval/23", "completion": "return len(string)\n"} -{"task_id": "HumanEval/24", "completion": "for i in range(n - 1, 0, -1):\n if n % i == 0:\n return i\n"} -{"task_id": "HumanEval/25", "completion": "def factorize(n: int) -> List[int]:\n factors = []\n while n % 2 == 0:\n factors.append(2)\n n //= 2\n for i in range(3, int(n**0.5) + 1, 2):\n while n % i == 0:\n factors.append(i)\n n //= i\n if n > 2:\n factors.append(n)\n return factors\n"} -{"task_id": "HumanEval/26", "completion": "def remove_duplicates(numbers: List[int]) -> List[int]:\n counts = {}\n for number in numbers:\n counts[number] = counts.get(number, 0) + 1\n \n return [number for number in numbers if counts[number] == 1]\n"} -{"task_id": "HumanEval/27", "completion": "return string.swapcase()\n"} -{"task_id": "HumanEval/28", "completion": "def concatenate(strings: List[str]) -> str:\n return ''.join(strings)\n"} -{"task_id": "HumanEval/29", "completion": "def filter_by_prefix(strings: List[str], prefix: str) -> List[str]:\n return [s for s in strings if s.startswith(prefix)]\n"} -{"task_id": "HumanEval/30", "completion": "def get_positive(l: list):\n return [num for num in l if num > 0]\n"} -{"task_id": "HumanEval/31", "completion": "def is_prime(n):\n if n < 2:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n"} -{"task_id": "HumanEval/32", "completion": "def find_zero(xs: list):\n \"\"\" xs are coefficients of a polynomial. \n find_zero finds x such that poly(x) = 0.\n \"\"\"\n # Contains the polynomial function\n def poly_derivative(xs, x):\n \"\"\" Evaluates the derivative of polynomial with coefficients xs at point x. \"\"\"\n return sum([i * coeff * math.pow(x, i - 1) for i, coeff in enumerate(xs) if i > 0])\n\n # Starting guess can be 0\n x0 = 0.0\n tolerance = 1e-7\n max_iterations = 1000\n for _ in range(max_iterations):\n fx = poly(xs, x0)\n dfx = poly_derivative(xs, x0)\n \n if dfx == 0: # Prevent division by zero\n break\n \n x1 = x0 - fx / dfx\n if abs(x1 - x0) < tolerance: # Check for convergence\n return x1\n x0 = x1\n \n return x0 # Return the last approximation\n"} -{"task_id": "HumanEval/33", "completion": "def sort_third(l: list):\n sorted_third = sorted(l[i] for i in range(len(l)) if i % 3 == 0)\n \n result = l[:]\n j = 0\n for i in range(len(l)):\n if i % 3 == 0:\n result[i] = sorted_third[j]\n j += 1\n\n return result\n"} -{"task_id": "HumanEval/34", "completion": "return sorted(set(l))\n"} -{"task_id": "HumanEval/35", "completion": "def max_element(l: list):\n return max(l)\n"} -{"task_id": "HumanEval/36", "completion": "count = 0\nfor i in range(n):\n if i % 11 == 0 or i % 13 == 0:\n count += str(i).count('7')\nreturn count\n"} -{"task_id": "HumanEval/37", "completion": "def sort_even(l: list):\n even_indices = sorted(l[i] for i in range(0, len(l), 2))\n result = []\n even_index = 0\n for i in range(len(l)):\n if i % 2 == 0:\n result.append(even_indices[even_index])\n even_index += 1\n else:\n result.append(l[i])\n return result\n"} -{"task_id": "HumanEval/38", "completion": "groups = [s[(3 * i):min((3 * i + 3), len(s))] for i in range((len(s) + 2) // 3)]\n groups = [(group[-1] + group[:-1]) if len(group) == 3 else group for group in groups]\n return \"\".join(groups)\n"} -{"task_id": "HumanEval/39", "completion": "def is_prime(num):\n if num < 2:\n return False\n for i in range(2, int(num**0.5) + 1):\n if num % i == 0:\n return False\n return True\n\ndef prime_fib(n: int):\n fib1, fib2 = 0, 1\n prime_fib_count = 0\n current_prime_fib = None\n\n while prime_fib_count < n:\n fib1, fib2 = fib2, fib1 + fib2\n if is_prime(fib2):\n prime_fib_count += 1\n current_prime_fib = fib2\n\n return current_prime_fib\n"} -{"task_id": "HumanEval/40", "completion": "def triples_sum_to_zero(l):\n n = len(l)\n for i in range(n):\n s = set()\n current_sum = -l[i]\n for j in range(i + 1, n):\n if (current_sum - l[j]) in s:\n return True\n s.add(l[j])\n return False\n"} -{"task_id": "HumanEval/41", "completion": "def car_race_collision(n: int) -> int:\n return n * n\n"} -{"task_id": "HumanEval/42", "completion": "def incr_list(l):\n return [x + 1 for x in l]\n"} -{"task_id": "HumanEval/43", "completion": "def pairs_sum_to_zero(l):\n seen = set()\n for num in l:\n if -num in seen:\n return True\n seen.add(num)\n return False\n"} -{"task_id": "HumanEval/44", "completion": "result = \"\"\n while x > 0:\n remainder = x % base\n result = str(remainder) + result # Prepend remainder to the result\n x //= base # Divide x by base\n return result if result else \"0\" # Handle case where x is 0\n"} -{"task_id": "HumanEval/45", "completion": "def triangle_area(a, h):\n return 0.5 * a * h\n"} -{"task_id": "HumanEval/46", "completion": "def fib4(n: int) -> int:\n if n == 0:\n return 0\n elif n == 1:\n return 0\n elif n == 2:\n return 2\n elif n == 3:\n return 0\n\n fib_sequence = [0, 0, 2, 0]\n for i in range(4, n + 1):\n next_value = fib_sequence[-1] + fib_sequence[-2] + fib_sequence[-3] + fib_sequence[-4]\n fib_sequence.append(next_value)\n\n return fib_sequence[n]\n"} -{"task_id": "HumanEval/47", "completion": "l.sort()\n n = len(l)\n if n % 2 == 1: # odd length\n return l[n // 2]\n else: # even length\n return (l[n // 2 - 1] + l[n // 2]) / 2\n"} -{"task_id": "HumanEval/48", "completion": "return text == text[::-1]\n"} -{"task_id": "HumanEval/49", "completion": "return pow(2, n, p)\n"} -{"task_id": "HumanEval/50", "completion": "def decode_shift(s: str):\n return \"\".join([chr(((ord(ch) - 5 - ord(\"a\")) % 26) + ord(\"a\")) for ch in s])\n"} -{"task_id": "HumanEval/51", "completion": "def remove_vowels(text):\n vowels = \"aeiouAEIOU\"\n return ''.join([char for char in text if char not in vowels])\n"} -{"task_id": "HumanEval/52", "completion": "for number in l:\n if number >= t:\n return False\nreturn True\n"} -{"task_id": "HumanEval/53", "completion": "return x + y\n"} -{"task_id": "HumanEval/54", "completion": "return set(s0) == set(s1)\n"} -{"task_id": "HumanEval/55", "completion": "if n == 1 or n == 2:\n return 1\n a, b = 1, 1\n for _ in range(3, n + 1):\n a, b = b, a + b\n return b\n"} -{"task_id": "HumanEval/56", "completion": "def correct_bracketing(brackets: str):\n count = 0\n for char in brackets:\n if char == \"<\":\n count += 1\n elif char == \">\":\n count -= 1\n if count < 0:\n return False\n return count == 0\n"} -{"task_id": "HumanEval/57", "completion": "def monotonic(l: list):\n if len(l) <= 1:\n return True\n\n increasing = decreasing = True\n\n for i in range(1, len(l)):\n if l[i] > l[i - 1]:\n decreasing = False\n elif l[i] < l[i - 1]:\n increasing = False\n\n return increasing or decreasing\n"} -{"task_id": "HumanEval/58", "completion": "def common(l1: list, l2: list):\n return sorted(set(l1) & set(l2))\n"} -{"task_id": "HumanEval/59", "completion": "def largest_prime_factor(n):\n largest_factor = 1\n # Check for number of 2s that divide n\n while n % 2 == 0:\n largest_factor = 2\n n //= 2\n \n # n must be odd at this point, thus check for odd factors from 3\n for i in range(3, int(n**0.5) + 1, 2):\n while n % i == 0:\n largest_factor = i\n n //= i\n \n # This condition is to check if n is a prime number\n # greater than 2\n if n > 2:\n largest_factor = n\n \n return largest_factor\n"} -{"task_id": "HumanEval/60", "completion": "def sum_to_n(n: int):\n return n * (n + 1) // 2\n"} -{"task_id": "HumanEval/61", "completion": "def correct_bracketing(brackets: str) -> bool:\n counter = 0\n for char in brackets:\n if char == '(':\n counter += 1\n elif char == ')':\n counter -= 1\n if counter < 0:\n return False\n return counter == 0\n"} -{"task_id": "HumanEval/62", "completion": "def derivative(xs):\n return [i * xs[i] for i in range(1, len(xs))]\n"} -{"task_id": "HumanEval/63", "completion": "def fibfib(n: int, memo={0: 0, 1: 0, 2: 1}):\n if n in memo:\n return memo[n]\n memo[n] = fibfib(n-1, memo) + fibfib(n-2, memo) + fibfib(n-3, memo)\n return memo[n]\n"} -{"task_id": "HumanEval/64", "completion": "def vowels_count(s):\n count = 0\n vowels = 'aeiou'\n \n for i, char in enumerate(s.lower()):\n if char in vowels or (char == 'y' and i == len(s) - 1):\n count += 1\n \n return count\n"} -{"task_id": "HumanEval/65", "completion": "def circular_shift(x, shift):\n s = str(x)\n length = len(s)\n \n if shift > length:\n return s[::-1]\n \n shift = shift % length\n return s[-shift:] + s[:-shift]\n"} -{"task_id": "HumanEval/66", "completion": "def digitSum(s):\n return sum(ord(char) for char in s if char.isupper())\n "} -{"task_id": "HumanEval/67", "completion": "def fruit_distribution(s, n):\n apples = int(s.split()[0]) \n oranges = int(s.split()[3]) \n \n mangoes = n - apples - oranges\n return mangoes\n"} -{"task_id": "HumanEval/68", "completion": "def pluck(arr):\n smallest_even = float('inf')\n smallest_index = -1\n \n for index, value in enumerate(arr):\n if value % 2 == 0: # Check if the value is even\n if value < smallest_even: # Check if it's the smallest even value\n smallest_even = value\n smallest_index = index\n\n if smallest_index == -1: # No even numbers found\n return []\n \n return [smallest_even, smallest_index]\n"} -{"task_id": "HumanEval/69", "completion": "def search(lst):\n frequency = {}\n \n # Count frequency of each number\n for num in lst:\n if num in frequency:\n frequency[num] += 1\n else:\n frequency[num] = 1\n\n # Check for the greatest integer that meets the condition\n for num in sorted(frequency.keys(), reverse=True):\n if frequency[num] >= num:\n return num\n \n return -1\n"} -{"task_id": "HumanEval/70", "completion": "def strange_sort_list(lst):\n lst.sort()\n result = []\n min_ptr, max_ptr = 0, len(lst) - 1\n \n while min_ptr <= max_ptr:\n if min_ptr == max_ptr:\n result.append(lst[min_ptr])\n else:\n result.append(lst[min_ptr])\n result.append(lst[max_ptr])\n \n min_ptr += 1\n max_ptr -= 1\n \n return result\n"} -{"task_id": "HumanEval/71", "completion": "def triangle_area(a, b, c):\n if a + b > c and a + c > b and b + c > a: # Check validity\n s = (a + b + c) / 2 # Semi-perimeter\n area = (s * (s - a) * (s - b) * (s - c)) ** 0.5 # Heron's formula\n return round(area, 2) # Return area rounded to 2 decimal points\n return -1 # Not a valid triangle\n"} -{"task_id": "HumanEval/72", "completion": "def will_it_fly(q, w):\n return q == q[::-1] and sum(q) <= w\n"} -{"task_id": "HumanEval/73", "completion": "def smallest_change(arr):\n changes = 0\n n = len(arr)\n \n for i in range(n // 2):\n if arr[i] != arr[n - 1 - i]:\n changes += 1\n \n return changes\n"} -{"task_id": "HumanEval/74", "completion": "def total_match(lst1, lst2):\n total_chars_lst1 = sum(len(s) for s in lst1)\n total_chars_lst2 = sum(len(s) for s in lst2)\n\n if total_chars_lst1 < total_chars_lst2:\n return lst1\n elif total_chars_lst1 > total_chars_lst2:\n return lst2\n else:\n return lst1\n"} -{"task_id": "HumanEval/75", "completion": "def is_multiply_prime(a):\n primes = [prime(i) for i in range(1, 30) if prime(i) < 100]\n for combo in combinations(primes, 3):\n if combo[0] * combo[1] * combo[2] == a:\n return True\n return False\n"} -{"task_id": "HumanEval/76", "completion": "def is_simple_power(x, n):\n if n <= 1:\n return x == n\n power = 1\n while power < x:\n power *= n\n return power == x\n"} -{"task_id": "HumanEval/77", "completion": "return round(abs(a) ** (1/3)) ** 3 == abs(a)\n"} -{"task_id": "HumanEval/78", "completion": "prime_hex_digits = {'2', '3', '5', '7', 'B', 'D'}\ncount = 0\n\nfor digit in num:\n if digit in prime_hex_digits:\n count += 1\n\nreturn count\n"} -{"task_id": "HumanEval/79", "completion": "def decimal_to_binary(decimal):\n return 'db' + bin(decimal)[2:] + 'db'\n"} -{"task_id": "HumanEval/80", "completion": "def is_happy(s):\n if len(s) < 3:\n return False\n for i in range(len(s) - 2):\n if len(set(s[i:i + 3])) < 3:\n return False\n return True\n"} -{"task_id": "HumanEval/81", "completion": "def numerical_letter_grade(grades):\n letter_grades = []\n for gpa in grades:\n if gpa == 4.0:\n letter_grades.append('A+')\n elif gpa > 3.7:\n letter_grades.append('A')\n elif gpa > 3.3:\n letter_grades.append('A-')\n elif gpa > 3.0:\n letter_grades.append('B+')\n elif gpa > 2.7:\n letter_grades.append('B')\n elif gpa > 2.3:\n letter_grades.append('B-')\n elif gpa > 2.0:\n letter_grades.append('C+')\n elif gpa > 1.7:\n letter_grades.append('C')\n elif gpa > 1.3:\n letter_grades.append('C-')\n elif gpa > 1.0:\n letter_grades.append('D+')\n elif gpa > 0.7:\n letter_grades.append('D')\n elif gpa > 0.0:\n letter_grades.append('D-')\n else:\n letter_grades.append('E')\n return letter_grades\n"} -{"task_id": "HumanEval/82", "completion": "def prime_length(string):\n def is_prime(n):\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n \n length = len(string)\n return is_prime(length)\n"} -{"task_id": "HumanEval/83", "completion": "def starts_one_ends(n):\n if n <= 0:\n return 0\n # Numbers starting with 1\n start_with_1 = 10**(n-1) # 1 followed by (n-1) zeros\n # Numbers ending with 1\n end_with_1 = 10**(n-1)\n\n # Counting overlaps (i.e., numbers that both start and end with 1)\n # These are of the form 1...1, and there are (n-2) digits in between\n overlap_count = 10**(n-2) if n > 1 else 1\n\n return start_with_1 + end_with_1 - overlap_count\n "} -{"task_id": "HumanEval/84", "completion": "def solve(N):\n if not (0 <= N <= 10000):\n raise ValueError(\"N must be between 0 and 10000\")\n\n digit_sum = sum(int(digit) for digit in str(N))\n return bin(digit_sum)[2:]\n"} -{"task_id": "HumanEval/85", "completion": "def add(lst):\n total = 0\n for index, value in enumerate(lst):\n if index % 2 != 0 and value % 2 == 0:\n total += value\n return total\n"} -{"task_id": "HumanEval/86", "completion": "def anti_shuffle(s):\n result = []\n for word in s.split(' '):\n sorted_word = ''.join(sorted(word))\n result.append(sorted_word)\n return ' '.join(result)\n"} -{"task_id": "HumanEval/87", "completion": "coordinates = []\n\nfor row_index, row in enumerate(lst):\n for col_index, value in enumerate(row):\n if value == x:\n coordinates.append((row_index, col_index))\n\ncoordinates.sort(key=lambda coord: (coord[0], -coord[1]))\n\nreturn coordinates\n"} -{"task_id": "HumanEval/88", "completion": "def sort_array(array):\n sum_first_last = array[0] + array[-1] if array else 0\n return sorted(array) if sum_first_last % 2 != 0 else sorted(array, reverse=True)\n"} -{"task_id": "HumanEval/89", "completion": "def encrypt(s):\n result = \"\"\n for char in s:\n if 'a' <= char <= 'z': # Check if char is a lowercase letter\n new_char = chr((ord(char) - ord('a') + 4) % 26 + ord('a'))\n result += new_char\n return result\n"} -{"task_id": "HumanEval/90", "completion": "def next_smallest(lst):\n if not lst:\n return None\n unique_elements = list(set(lst))\n unique_elements.sort()\n if len(unique_elements) < 2:\n return None\n return unique_elements[1]\n"} -{"task_id": "HumanEval/91", "completion": "sentences = [s.strip() for s in re.split(r'[.!?]', S) if s] # Split into sentences\nreturn sum(1 for sentence in sentences if sentence.startswith(\"I\")) # Count \"I\"-starting sentences\n"} -{"task_id": "HumanEval/92", "completion": "def any_int(x, y, z):\n return all(isinstance(i, int) for i in (x, y, z)) and (\n x == y + z or y == x + z or z == x + y\n )\n"} -{"task_id": "HumanEval/93", "completion": "def encode(message):\n vowels = {'a': 'c', 'e': 'g', 'i': 'k', 'o': 'q', 'u': 'w',\n 'A': 'C', 'E': 'G', 'I': 'K', 'O': 'Q', 'U': 'W'}\n \n result = []\n for char in message:\n if char in vowels:\n result.append(vowels[char])\n elif char.isalpha():\n result.append(char.swapcase())\n else:\n result.append(char)\n \n return ''.join(result)\n"} -{"task_id": "HumanEval/94", "completion": "def skjkasdkd(lst):\n def is_prime(n):\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n \n largest_prime = None\n \n for num in lst:\n if is_prime(num):\n if largest_prime is None or num > largest_prime:\n largest_prime = num\n \n if largest_prime is None:\n return 0 # or some other default value if there's no prime\n \n return sum(int(digit) for digit in str(largest_prime))\n"} -{"task_id": "HumanEval/95", "completion": "def check_dict_case(d):\n if not d: # Check if the dictionary is empty\n return False\n \n keys = d.keys() # Get all keys from the dictionary\n all_lower = all(isinstance(k, str) and k.islower() for k in keys) # Check if all keys are lower case\n all_upper = all(isinstance(k, str) and k.isupper() for k in keys) # Check if all keys are upper case\n \n return all_lower or all_upper # Return True if either condition is met\n"} -{"task_id": "HumanEval/96", "completion": "def is_prime(num):\n if num < 2:\n return False\n for i in range(2, int(num**0.5) + 1):\n if num % i == 0:\n return False\n return True\n\ndef count_up_to(n):\n return [i for i in range(2, n) if is_prime(i)]\n"} -{"task_id": "HumanEval/97", "completion": "def multiply(a, b):\n # Get the unit digit of each number\n unit_digit_a = abs(a) % 10\n unit_digit_b = abs(b) % 10\n # Return the product of the unit digits\n return unit_digit_a * unit_digit_b\n "} -{"task_id": "HumanEval/98", "completion": "def count_upper(s):\n count = 0\n for i in range(0, len(s), 2):\n if s[i] in 'AEIOU':\n count += 1\n return count\n "} -{"task_id": "HumanEval/99", "completion": "number = float(value)\n floor_value = int(number) # Get the floor value of the number\n ceil_value = floor_value + 1 # Get the ceiling value\n \n if number - floor_value < 0.5:\n return floor_value\n elif number - floor_value > 0.5:\n return ceil_value\n else: # number - floor_value == 0.5\n return ceil_value if number > 0 else floor_value\n"} -{"task_id": "HumanEval/100", "completion": "def make_a_pile(n):\n stones = []\n current_stones = n\n \n for i in range(n):\n stones.append(current_stones)\n if current_stones % 2 == 0: # current_stones is even\n current_stones += 2 # next level will have the next even number\n else:\n current_stones += 2 # next level will have the next odd number\n \n return stones\n"} -{"task_id": "HumanEval/101", "completion": "import re\n\ndef words_string(s):\n return re.split(r'[ ,]+', s)\n"} -{"task_id": "HumanEval/102", "completion": "def choose_num(x, y):\n lower = min(x, y)\n upper = max(x, y)\n \n for num in range(upper, lower - 1, -1):\n if num % 2 == 0:\n return num\n return -1\n"} -{"task_id": "HumanEval/103", "completion": "def rounded_avg(n, m):\n if n > m:\n return -1\n avg = round((n + m) / 2)\n return bin(avg)\n"} -{"task_id": "HumanEval/104", "completion": "result = []\nfor num in x:\n if all(int(digit) % 2 != 0 for digit in str(num)): # Check if all digits are odd\n result.append(num)\nreturn sorted(result)\n"} -{"task_id": "HumanEval/105", "completion": "def by_length(arr):\n filtered = [x for x in arr if 1 <= x <= 9] # Step 1: Filter numbers\n sorted_arr = sorted(filtered) # Step 2: Sort the array\n reversed_arr = sorted_arr[::-1] # Step 3: Reverse the array\n\n # Step 4: Map integers to their names\n number_names = [\"One\", \"Two\", \"Three\", \"Four\", \"Five\", \"Six\", \"Seven\", \"Eight\", \"Nine\"]\n result = [number_names[x - 1] for x in reversed_arr] # Step 5: Replace with names\n return result\n"} -{"task_id": "HumanEval/106", "completion": "result = []\nfor i in range(1, n + 1):\n if i % 2 == 0: # i is even\n factorial = 1\n for j in range(1, i + 1):\n factorial *= j\n result.append(factorial)\n else: # i is odd\n sum_odd = sum(range(1, i + 1))\n result.append(sum_odd)\nreturn result\n"} -{"task_id": "HumanEval/107", "completion": "def even_odd_palindrome(n):\n def is_palindrome(num):\n return str(num) == str(num)[::-1]\n \n odd_count = 0\n even_count = 0\n \n for i in range(1, n + 1):\n if is_palindrome(i):\n if i % 2 == 0:\n even_count += 1\n else:\n odd_count += 1\n \n return (even_count, odd_count)\n"} -{"task_id": "HumanEval/108", "completion": "def count_nums(arr):\n count = 0\n for num in arr:\n digit_sum = sum(int(digit) if num >= 0 else -int(digit) for digit in str(abs(num)))\n if digit_sum > 0:\n count += 1\n return count\n"} -{"task_id": "HumanEval/109", "completion": "def move_one_ball(arr):\n if not arr:\n return True\n\n descents = 0\n n = len(arr)\n\n for i in range(n):\n if arr[i] > arr[(i + 1) % n]: # Use modulo to wrap around\n descents += 1\n\n return descents <= 1\n"} -{"task_id": "HumanEval/110", "completion": "def exchange(lst1, lst2):\n odd_count = sum(1 for x in lst1 if x % 2 != 0)\n even_count_in_lst2 = sum(1 for x in lst2 if x % 2 == 0)\n if odd_count <= even_count_in_lst2:\n return \"YES\"\n else:\n return \"NO\"\n"} -{"task_id": "HumanEval/111", "completion": "def histogram(test):\n counts = {}\n \n # Split the input string into letters and count occurrences\n for letter in test.split():\n counts[letter] = counts.get(letter, 0) + 1\n \n if not counts:\n return {}\n \n # Find the maximum count\n max_count = max(counts.values())\n \n # Gather all letters with the maximum count\n result = {letter: count for letter, count in counts.items() if count == max_count}\n \n return result\n"} -{"task_id": "HumanEval/112", "completion": "def reverse_delete(s, c):\n result = ''.join(char for char in s if char not in c) # Step 1: Remove characters\n is_palindrome = result == result[::-1] # Step 2: Check for palindrome\n return result, is_palindrome # Step 3: Return result\n"} -{"task_id": "HumanEval/113", "completion": "def odd_count(lst):\n result = []\n for s in lst:\n odd_count = sum(1 for char in s if char in '13579')\n result.append(f\"the number of odd elements {odd_count}n the str{odd_count}ng {odd_count} of the {odd_count}nput.\")\n return result\n"} -{"task_id": "HumanEval/114", "completion": "def minSubArraySum(nums):\n min_sum = float('inf')\n current_sum = 0\n\n for num in nums:\n current_sum += num\n if current_sum < min_sum:\n min_sum = current_sum\n if current_sum > 0:\n current_sum = 0\n\n return min_sum\n"} -{"task_id": "HumanEval/115", "completion": "def max_fill(grid, capacity):\n total_water = 0\n \n # Count total water in the grid\n for row in grid:\n total_water += sum(row)\n \n # Calculate number of times to lower buckets\n return math.ceil(total_water / capacity)\n"} -{"task_id": "HumanEval/116", "completion": "def sort_array(arr):\n arr.sort(key=lambda x: (bin(x).count('1'), x))\n return arr\n"} -{"task_id": "HumanEval/117", "completion": "def select_words(s, n):\n if not s:\n return []\n \n def count_consonants(word):\n consonants = \"bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ\"\n return sum(1 for char in word if char in consonants)\n \n words = s.split()\n result = [word for word in words if count_consonants(word) == n]\n \n return result\n"} -{"task_id": "HumanEval/118", "completion": "def get_closest_vowel(word):\n vowels = 'aeiouAEIOU'\n last_consonants = []\n \n # Traverse the string from right to left\n for char in reversed(word):\n if char in vowels:\n # Check for vowels between two consonants\n if len(last_consonants) == 2:\n return char\n elif char.isalpha(): # It is a consonant\n last_consonants.append(char)\n # Keep only the last two consonants\n if len(last_consonants) > 2:\n last_consonants.pop(0)\n\n return \"\"\n"} -{"task_id": "HumanEval/119", "completion": "def match_parens(lst):\n s1, s2 = lst\n\n def is_balanced(s1, s2):\n count = 0\n for char in s1 + s2:\n if char == '(':\n count += 1\n else:\n count -= 1\n if count < 0:\n return False\n return count == 0\n\n return 'Yes' if is_balanced(s1, s2) or is_balanced(s2, s1) else 'No'\n"} -{"task_id": "HumanEval/120", "completion": "def maximum(arr, k):\n return sorted(sorted(arr)[-k:])\n"} -{"task_id": "HumanEval/121", "completion": "total_sum = sum(lst[i] for i in range(len(lst)) if i % 2 == 0 and lst[i] % 2 != 0)\nreturn total_sum\n"} -{"task_id": "HumanEval/122", "completion": "def add_elements(arr, k):\n return sum(x for x in arr[:k] if -10 < x < 100)\n "} -{"task_id": "HumanEval/123", "completion": "def get_odd_collatz(n):\n odd_numbers = []\n \n while n != 1:\n if n % 2 != 0: # n is odd\n odd_numbers.append(n)\n n = n // 2 if n % 2 == 0 else 3 * n + 1\n \n odd_numbers.append(1) # Append 1 as it's also considered odd\n return sorted(odd_numbers)\n"} -{"task_id": "HumanEval/124", "completion": "def valid_date(date):\n if not date:\n return False\n \n if date.count('-') != 2:\n return False\n \n month, day, year = date.split('-')\n \n try:\n month = int(month)\n day = int(day)\n year = int(year)\n except ValueError:\n return False\n \n if month < 1 or month > 12:\n return False\n \n if month in [1, 3, 5, 7, 8, 10, 12]:\n if day < 1 or day > 31:\n return False\n elif month in [4, 6, 9, 11]:\n if day < 1 or day > 30:\n return False\n elif month == 2:\n if day < 1 or day > 29:\n return False\n \n return True\n"} -{"task_id": "HumanEval/125", "completion": "def split_words(txt):\n if any(char.isspace() for char in txt):\n return txt.split()\n elif ',' in txt:\n return txt.split(',')\n else:\n return sum(1 for char in txt if char.islower() and (ord(char) - ord('a')) % 2 == 0)\n"} -{"task_id": "HumanEval/126", "completion": "def is_sorted(lst):\n return lst == sorted(lst) and len(lst) == len(set(lst))\n"} -{"task_id": "HumanEval/127", "completion": "def intersection(interval1, interval2):\n start1, end1 = interval1\n start2, end2 = interval2\n\n # Calculate the intersection\n start_intersection = max(start1, start2)\n end_intersection = min(end1, end2)\n\n # Check if there is an intersection\n if start_intersection >= end_intersection:\n return \"NO\"\n\n # Calculate length of the intersection\n length = end_intersection - start_intersection\n\n # Function to check if a number is prime\n def is_prime(n):\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n\n # Check if the length of the intersection is prime\n if is_prime(length):\n return \"YES\"\n else:\n return \"NO\"\n"} -{"task_id": "HumanEval/128", "completion": "def prod_signs(arr):\n if not arr:\n return None\n \n product_of_signs = 1\n sum_of_magnitudes = 0\n \n for num in arr:\n if num > 0:\n sum_of_magnitudes += num\n elif num < 0:\n sum_of_magnitudes += -num\n product_of_signs *= -1\n else: # num == 0\n product_of_signs = 0\n \n return sum_of_magnitudes * product_of_signs\n"} -{"task_id": "HumanEval/129", "completion": "def minPath(grid, k):\n from itertools import product\n \n n = len(grid)\n best_path = []\n\n def dfs(r, c, path):\n nonlocal best_path\n \n if len(path) == k:\n if not best_path or path < best_path:\n best_path = path[:]\n return\n \n directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]\n for dr, dc in directions:\n nr, nc = r + dr, c + dc\n if 0 <= nr < n and 0 <= nc < n:\n path.append(grid[nr][nc])\n dfs(nr, nc, path)\n path.pop()\n\n for i, j in product(range(n), repeat=2):\n dfs(i, j, [grid[i][j]])\n\n return best_path\n"} -{"task_id": "HumanEval/130", "completion": "def tri(n):\n tribonacci = []\n \n for i in range(n + 1):\n if i == 0:\n tribonacci.append(1)\n elif i == 1:\n tribonacci.append(3)\n elif i % 2 == 0: # Even\n tribonacci.append(1 + i / 2)\n else: # Odd\n tribonacci.append(\n tribonacci[i - 1] + tribonacci[i - 2] + tribonacci[i + 1] if (i + 1 <= n) else tribonacci[i - 1] + tribonacci[i - 2]\n )\n \n return tribonacci\n"} -{"task_id": "HumanEval/131", "completion": "def digits(n):\n product = 1\n has_odd = False\n while n > 0:\n digit = n % 10\n if digit % 2 != 0: # Check if the digit is odd\n product *= digit\n has_odd = True\n n //= 10 # Remove the last digit\n return product if has_odd else 0\n "} -{"task_id": "HumanEval/132", "completion": "def is_nested(string):\n stack = []\n nested = False\n\n for char in string:\n if char == '[':\n stack.append(char)\n elif char == ']':\n if stack:\n top = stack.pop()\n if stack: # Check if there are still brackets in the stack\n nested = True # We found a nested bracket\n else:\n return False # More closing brackets than opening\n\n # If there are still items in stack, that means we have unmatched opening brackets\n return nested\n\n# Example tests\nprint(is_nested('[[]]')) # \u279e True\nprint(is_nested('[]]]]]]][[[[[]')) # \u279e False\nprint(is_nested('[][]')) # \u279e False\nprint(is_nested('[]')) # \u279e False\nprint(is_nested('[[][]]')) # \u279e True\nprint(is_nested('[[]][[')) # \u279e True\n"} -{"task_id": "HumanEval/133", "completion": "import math\n\ndef sum_squares(lst):\n return sum(math.ceil(x) ** 2 for x in lst)\n"} -{"task_id": "HumanEval/134", "completion": "def check_if_last_char_is_a_letter(txt):\n txt = txt.rstrip() # Remove trailing spaces\n if len(txt) == 0: # Check if the string is empty\n return False\n last_char = txt[-1] # Get the last character\n\n # Check if last_char is a letter and is not part of a word\n return last_char.isalpha() and (len(txt) == 1 or txt[-2] == ' ')\n"} -{"task_id": "HumanEval/135", "completion": "for i in range(1, len(arr)):\n if arr[i] < arr[i - 1]:\n return i\n return -1\n"} -{"task_id": "HumanEval/136", "completion": "largest_smallest_integers(lst):\n largest_negative = None\n smallest_positive = None\n \n for number in lst:\n if number < 0:\n if largest_negative is None or number > largest_negative:\n largest_negative = number\n elif number > 0:\n if smallest_positive is None or number < smallest_positive:\n smallest_positive = number\n\n return (largest_negative, smallest_positive)\n"} -{"task_id": "HumanEval/137", "completion": "def compare_one(a, b):\n def to_float(value):\n if isinstance(value, str):\n value = value.replace(',', '.') \n return float(value)\n\n try:\n float_a = to_float(a)\n float_b = to_float(b)\n except ValueError:\n return None\n\n if float_a > float_b:\n return a\n elif float_a < float_b:\n return b\n else:\n return None\n"} -{"task_id": "HumanEval/138", "completion": "def is_equal_to_sum_even(n):\n return n >= 8 and n % 2 == 0\n"} -{"task_id": "HumanEval/139", "completion": "def special_factorial(n):\n def factorial(x):\n if x == 0 or x == 1:\n return 1\n else:\n result = 1\n for i in range(2, x + 1):\n result *= i\n return result\n\n result = 1\n for i in range(1, n + 1):\n result *= factorial(i)\n \n return result\n"} -{"task_id": "HumanEval/140", "completion": "def fix_spaces(text):\n import re\n text = text.lstrip(' ')\n text = re.sub(r' {2,}', '-', text)\n text = text.replace(' ', '_')\n if text.startswith('_'):\n text = '_' + text.strip('_')\n return text\n"} -{"task_id": "HumanEval/141", "completion": "def file_name_check(file_name):\n # Check for one dot\n if file_name.count('.') != 1:\n return 'No'\n \n # Split the name into the part before and after the dot\n name_part, ext_part = file_name.split('.')\n \n # Check if the name part is empty and starts with a letter\n if not name_part or not name_part[0].isalpha():\n return 'No'\n \n # Check for valid file extensions\n valid_extensions = ['txt', 'exe', 'dll']\n if ext_part not in valid_extensions:\n return 'No'\n \n # Count the digits in the file name\n digit_count = sum(c.isdigit() for c in file_name)\n if digit_count > 3:\n return 'No'\n \n return 'Yes'\n"} -{"task_id": "HumanEval/142", "completion": "def sum_squares(lst):\n total_sum = 0\n for index, value in enumerate(lst):\n if index % 3 == 0:\n total_sum += value ** 2\n elif index % 4 == 0:\n total_sum += value ** 3\n else:\n total_sum += value\n return total_sum\n"} -{"task_id": "HumanEval/143", "completion": "def words_in_sentence(sentence):\n def is_prime(n):\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n\n words = sentence.split()\n prime_length_words = [word for word in words if is_prime(len(word))]\n return ' '.join(prime_length_words)\n"} -{"task_id": "HumanEval/144", "completion": "def simplify(x, n):\n num1, denom1 = map(int, x.split('/'))\n num2, denom2 = map(int, n.split('/'))\n \n result_numerator = num1 * num2\n result_denominator = denom1 * denom2\n \n return result_numerator % result_denominator == 0\n"} -{"task_id": "HumanEval/145", "completion": "def order_by_points(nums):\n def sum_of_digits(n):\n return sum(int(digit) for digit in str(abs(n)))\n\n return sorted(nums, key=lambda x: (sum_of_digits(x), nums.index(x)))\n"} -{"task_id": "HumanEval/146", "completion": "def specialFilter(nums):\n count = 0\n for num in nums:\n if num > 10:\n num_str = str(num)\n first_digit = int(num_str[0])\n last_digit = int(num_str[-1])\n if first_digit % 2 != 0 and last_digit % 2 != 0:\n count += 1\n return count\n"} -{"task_id": "HumanEval/147", "completion": "a = [i * i - i + 1 for i in range(1, n + 1)]\ncount = 0\n\n# Iterate through all possible triples\nfor i in range(n):\n for j in range(i + 1, n):\n for k in range(j + 1, n):\n if (a[i] + a[j] + a[k]) % 3 == 0:\n count += 1\n \nreturn count\n"} -{"task_id": "HumanEval/148", "completion": "def bf(planet1, planet2):\n planets = [\"Mercury\", \"Venus\", \"Earth\", \"Mars\", \"Jupiter\", \"Saturn\", \"Uranus\", \"Neptune\"]\n if planet1 not in planets or planet2 not in planets:\n return ()\n \n index1 = planets.index(planet1)\n index2 = planets.index(planet2)\n \n if index1 > index2:\n index1, index2 = index2, index1\n \n return tuple(planets[index1 + 1:index2])\n"} -{"task_id": "HumanEval/149", "completion": "def sorted_list_sum(lst):\n # Remove strings with odd lengths\n filtered = [s for s in lst if len(s) % 2 == 0]\n # Sort by length and then alphabetically\n sorted_list = sorted(filtered, key=lambda x: (len(x), x))\n return sorted_list\n"} -{"task_id": "HumanEval/150", "completion": "def x_or_y(n, x, y):\n def is_prime(num):\n if num <= 1:\n return False\n for i in range(2, int(num**0.5) + 1):\n if num % i == 0:\n return False\n return True\n \n return x if is_prime(n) else y\n"} -{"task_id": "HumanEval/151", "completion": "def double_the_difference(lst):\n odd_squares_sum = sum(x ** 2 for x in lst if x >= 0 and x % 2 == 1)\n return odd_squares_sum\n"} -{"task_id": "HumanEval/152", "completion": "def compare(game, guess):\n return [abs(g - s) for g, s in zip(guess, game)]\n"} -{"task_id": "HumanEval/153", "completion": "def Strongest_Extension(class_name, extensions):\n strongest_extension = \"\"\n max_strength = float('-inf') # Initialize to negative infinity to find the max\n\n for extension in extensions:\n CAP = sum(1 for char in extension if char.isupper())\n SM = sum(1 for char in extension if char.islower())\n strength = CAP - SM\n \n if strength > max_strength: # Update if this extension is stronger\n max_strength = strength\n strongest_extension = extension\n\n return f\"{class_name}.{strongest_extension}\"\n"} -{"task_id": "HumanEval/154", "completion": "def cycpattern_check(a, b):\n if len(b) == 0:\n return True\n return any(b[i:i+len(b)] in a for i in range(len(b)))\n"} -{"task_id": "HumanEval/155", "completion": "even_count = 0\n odd_count = 0\n\n for digit in str(abs(num)):\n if int(digit) % 2 == 0:\n even_count += 1\n else:\n odd_count += 1\n\n return (even_count, odd_count)\n"} -{"task_id": "HumanEval/156", "completion": "def int_to_mini_roman(number):\n roman_numerals = [\n (1000, 'm'), (900, 'cm'), (500, 'd'), (400, 'cd'),\n (100, 'c'), (90, 'xc'), (50, 'l'), (40, 'xl'),\n (10, 'x'), (9, 'ix'), (5, 'v'), (4, 'iv'), (1, 'i')\n ]\n \n result = \"\"\n \n for value, numeral in roman_numerals:\n while number >= value:\n result += numeral\n number -= value\n \n return result\n"} -{"task_id": "HumanEval/157", "completion": "sides = sorted([a, b, c])\nreturn sides[0]**2 + sides[1]**2 == sides[2]**2\n"} -{"task_id": "HumanEval/158", "completion": "def find_max(words):\n max_word = \"\"\n max_unique_count = 0\n \n for word in words:\n unique_chars = len(set(word))\n \n if (unique_chars > max_unique_count or \n (unique_chars == max_unique_count and word < max_word)):\n max_word = word\n max_unique_count = unique_chars\n \n return max_word\n"} -{"task_id": "HumanEval/159", "completion": "def eat(number, need, remaining):\n total_eaten = number\n if need <= remaining:\n total_eaten += need\n remaining -= need\n else:\n total_eaten += remaining\n remaining = 0\n return [total_eaten, remaining]\n"} -{"task_id": "HumanEval/160", "completion": "def do_algebra(operator, operand):\n result = operand[0]\n for i in range(len(operator)):\n if operator[i] == '+':\n result += operand[i + 1]\n elif operator[i] == '-':\n result -= operand[i + 1]\n elif operator[i] == '*':\n result *= operand[i + 1]\n elif operator[i] == '//':\n result //= operand[i + 1]\n elif operator[i] == '**':\n result **= operand[i + 1]\n return result\n"} -{"task_id": "HumanEval/161", "completion": "def solve(s):\n # Check if there are any letters in the input string\n has_letter = any(c.isalpha() for c in s)\n\n if not has_letter:\n # Reverse the string if no letters are present\n return s[::-1]\n else:\n # Create a list to hold the new characters\n result = []\n # Iterate through each character in the string\n for c in s:\n if c.isalpha():\n # Reverse case for letters\n if c.islower():\n result.append(c.upper())\n else:\n result.append(c.lower())\n else:\n # Keep non-letter characters as they are\n result.append(c)\n return ''.join(result)\n "} -{"task_id": "HumanEval/162", "completion": "import hashlib\n\ndef string_to_md5(text):\n if text == \"\":\n return None\n hash_object = hashlib.md5(text.encode())\n return hash_object.hexdigest()\n"} -{"task_id": "HumanEval/163", "completion": "def generate_integers(a, b):\n lower = min(a, b)\n upper = max(a, b)\n return [n for n in range(lower, upper + 1) if n % 2 == 0]\n"} +{"task_id": "HumanEval/0", "completion": "for i in range(len(numbers)):\n for j in range(i + 1, len(numbers)):\n if abs(numbers[i] - numbers[j]) < threshold:\n return True\n return False\n "} +{"task_id": "HumanEval/1", "completion": " stack = []\n result = []\n current_group = ''\n\n for char in paren_string:\n if char == '(': \n if len(stack) == 0:\n current_group = char\n else:\n current_group += char\n stack.append(char)\n elif char == ')':\n current_group += char\n stack.pop()\n if len(stack) == 0:\n result.append(current_group)\n current_group = ''\n\n return result\n\n "} +{"task_id": "HumanEval/2", "completion": " return number - int(number)\n\n "} +{"task_id": "HumanEval/3", "completion": "balance = 0\n for operation in operations:\n balance += operation\n if balance < 0:\n return True\n return False\n "} +{"task_id": "HumanEval/4", "completion": "mean = sum(numbers) / len(numbers)\n return sum(abs(x - mean) for x in numbers) / len(numbers)\n "} +{"task_id": "HumanEval/5", "completion": "if not numbers:\n return []\n result = []\n for i in range(len(numbers) - 1):\n result.append(numbers[i])\n result.append(delimeter)\n result.append(numbers[-1])\n return result\n "} +{"task_id": "HumanEval/6", "completion": "groups = paren_string.split()\n max_depths = []\n\n for group in groups:\n current_depth = 0\n max_depth = 0\n \n for char in group:\n if char == '(':\n current_depth += 1\n max_depth = max(max_depth, current_depth)\n elif char == ')':\n current_depth -= 1\n\n max_depths.append(max_depth)\n\n return max_depths\n "} +{"task_id": "HumanEval/7", "completion": "return [s for s in strings if substring in s]\n "} +{"task_id": "HumanEval/8", "completion": "if not numbers:\n return (0, 1)\n \n total_sum = 0\n total_product = 1\n \n for number in numbers:\n total_sum += number\n total_product *= number\n \n return (total_sum, total_product)\n "} +{"task_id": "HumanEval/9", "completion": "rolling_max = []\n current_max = float('-inf')\n for number in numbers:\n current_max = max(current_max, number)\n rolling_max.append(current_max)\n return rolling_max\n "} +{"task_id": "HumanEval/10", "completion": "# Check for empty string\n if string == '':\n return ''\n \n # Find the longest palindromic suffix\n for i in range(len(string)):\n if is_palindrome(string[i:]):\n # The prefix that needs to be mirrored\n prefix = string[:i]\n # Create the palindrome\n return string + prefix[::-1]\n "} +{"task_id": "HumanEval/11", "completion": "return ''.join('1' if a[i] != b[i] else '0' for i in range(len(a)))\n "} +{"task_id": "HumanEval/12", "completion": "if not strings:\n return None\n longest_string = strings[0]\n for string in strings:\n if len(string) > len(longest_string):\n longest_string = string\n return longest_string\n "} +{"task_id": "HumanEval/13", "completion": "while b:\n a, b = b, a % b\nreturn a\n "} +{"task_id": "HumanEval/14", "completion": "return [string[:i] for i in range(1, len(string) + 1)]\n "} +{"task_id": "HumanEval/15", "completion": "return ' '.join(str(i) for i in range(n + 1))\n "} +{"task_id": "HumanEval/16", "completion": "return len(set(string.lower()))\n "} +{"task_id": "HumanEval/17", "completion": "notes = music_string.split()\nnote_to_beats = {\n 'o': 4,\n 'o|': 2,\n '.|': 1\n}\n\nreturn [note_to_beats[note] for note in notes]\n "} +{"task_id": "HumanEval/18", "completion": "count = 0\nstart = 0\nwhile True:\n start = string.find(substring, start)\n if start == -1:\n break\n count += 1\n start += 1\nreturn count\n "} +{"task_id": "HumanEval/19", "completion": " num_map = {\n 'zero': 0, 'one': 1, 'two': 2, 'three': 3,\n 'four': 4, 'five': 5, 'six': 6, 'seven': 7,\n 'eight': 8, 'nine': 9\n }\n \n # Split the input string and map to integers\n num_list = [num_map[num] for num in numbers.split()]\n \n # Sort the list of numbers\n num_list.sort()\n \n # Convert back to the word representation\n sorted_numbers = ' '.join(num_map_inv[num] for num in num_list)\n \n return sorted_numbers\n "} +{"task_id": "HumanEval/20", "completion": "numbers.sort()\n min_diff = float('inf')\n closest_pair = (0, 0)\n\n for i in range(len(numbers) - 1):\n diff = numbers[i + 1] - numbers[i]\n if diff < min_diff:\n min_diff = diff\n closest_pair = (numbers[i], numbers[i + 1])\n \n return closest_pair\n "} +{"task_id": "HumanEval/21", "completion": "min_val = min(numbers)\n max_val = max(numbers)\n return [(num - min_val) / (max_val - min_val) for num in numbers]\n "} +{"task_id": "HumanEval/22", "completion": "return [value for value in values if isinstance(value, int)]\n "} +{"task_id": "HumanEval/23", "completion": "return len(string)\n "} +{"task_id": "HumanEval/24", "completion": "for i in range(n - 1, 0, -1):\n if n % i == 0:\n return i\n "} +{"task_id": "HumanEval/25", "completion": "factors = []\n divisor = 2\n while n > 1:\n while n % divisor == 0:\n factors.append(divisor)\n n //= divisor\n divisor += 1\n return factors\n "} +{"task_id": "HumanEval/26", "completion": "count = {}\n for num in numbers:\n count[num] = count.get(num, 0) + 1\n return [num for num in numbers if count[num] == 1]\n "} +{"task_id": "HumanEval/27", "completion": "return string.swapcase()\n "} +{"task_id": "HumanEval/28", "completion": "return ''.join(strings)\n "} +{"task_id": "HumanEval/29", "completion": "return [s for s in strings if s.startswith(prefix)]\n "} +{"task_id": "HumanEval/30", "completion": "return [x for x in l if x > 0]\n "} +{"task_id": "HumanEval/31", "completion": "if n < 2:\n return False\nfor i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\nreturn True\n "} +{"task_id": "HumanEval/32", "completion": " \"\"\"Calculates the derivative of the polynomial at point x.\"\"\"\n return sum([i * coeff * math.pow(x, i - 1) for i, coeff in enumerate(xs) if i > 0])\n\n x0 = 0 # Initial guess\n for _ in range(100): # Limit iterations to avoid infinite loops\n fx0 = poly(xs, x0)\n dfx0 = derivative(xs, x0)\n if dfx0 == 0: # Avoid division by zero\n raise ValueError(\"Derivative is zero; try a different initial guess.\")\n x1 = x0 - fx0 / dfx0 # Newton-Raphson step\n if abs(x1 - x0) < 1e-7: # Convergence criteria\n return x1\n x0 = x1\n \n raise ValueError(\"Root finding did not converge.\")\n "} +{"task_id": "HumanEval/33", "completion": "new_list = l[:]\n sorted_values = sorted([l[i] for i in range(len(l)) if i % 3 == 0])\n \n for index, value in enumerate(new_list):\n if index % 3 == 0:\n new_list[index] = sorted_values.pop(0)\n \n return new_list\n "} +{"task_id": "HumanEval/34", "completion": "return sorted(set(l))\n "} +{"task_id": "HumanEval/35", "completion": "return max(l)\n "} +{"task_id": "HumanEval/36", "completion": "count = 0\n for i in range(n):\n if i % 11 == 0 or i % 13 == 0:\n count += str(i).count('7')\n return count\n "} +{"task_id": "HumanEval/37", "completion": "even_vals = sorted(l[i] for i in range(len(l)) if i % 2 == 0)\nresult = []\n\nfor i in range(len(l)):\n if i % 2 == 0:\n result.append(even_vals.pop(0))\n else:\n result.append(l[i])\n\nreturn result\n "} +{"task_id": "HumanEval/38", "completion": "groups = [s[(3 * i):min((3 * i + 3), len(s))] for i in range((len(s) + 2) // 3)]\n groups = [(group[-1] + group[:-1]) if len(group) == 3 else group for group in groups]\n return \"\".join(groups)\n "} +{"task_id": "HumanEval/39", "completion": " if num <= 1:\n return False\n for i in range(2, int(num**0.5) + 1):\n if num % i == 0:\n return False\n return True\n\nfib1, fib2 = 1, 1\ncount = 0\nwhile True:\n fib1, fib2 = fib2, fib1 + fib2\n if is_prime(fib2):\n count += 1\n if count == n:\n return fib2\n "} +{"task_id": "HumanEval/40", "completion": " seen = set()\n pairs = set()\n for number in l:\n if -number in pairs:\n return True\n for x in seen:\n pairs.add(x + number)\n seen.add(number)\n return False\n "} +{"task_id": "HumanEval/41", "completion": " return n * n\n "} +{"task_id": "HumanEval/42", "completion": "return [x + 1 for x in l]\n "} +{"task_id": "HumanEval/43", "completion": "seen = set()\n for num in l:\n if -num in seen:\n return True\n seen.add(num)\n return False\n "} +{"task_id": "HumanEval/44", "completion": "if base < 2 or base > 9:\n raise ValueError(\"Base must be between 2 and 9.\")\n \n if x == 0:\n return '0'\n \n result = ''\n while x > 0:\n result = str(x % base) + result\n x //= base\n \n return result\n "} +{"task_id": "HumanEval/45", "completion": "return 0.5 * a * h\n "} +{"task_id": "HumanEval/46", "completion": "if n == 0: return 0\n if n == 1: return 0\n if n == 2: return 2\n if n == 3: return 0\n\n # Initial values corresponding to fib4(0), fib4(1), fib4(2) and fib4(3)\n a, b, c, d = 0, 0, 2, 0\n \n for i in range(4, n + 1):\n # Calculate fib4(i) as the sum of the previous four values\n fib_n = a + b + c + d\n # Update the previous values\n a, b, c, d = b, c, d, fib_n\n\n return d\n "} +{"task_id": "HumanEval/47", "completion": "l.sort()\n n = len(l)\n if n % 2 == 1:\n return l[n // 2]\n else:\n return (l[n // 2 - 1] + l[n // 2]) / 2\n "} +{"task_id": "HumanEval/48", "completion": "return text == text[::-1]\n "} +{"task_id": "HumanEval/49", "completion": "return pow(2, n, p)\n "} +{"task_id": "HumanEval/50", "completion": "return \"\".join([chr(((ord(ch) - 5 - ord(\"a\")) % 26) + ord(\"a\")) for ch in s])\n "} +{"task_id": "HumanEval/51", "completion": "return ''.join(char for char in text if char.lower() not in 'aeiou')\n "} +{"task_id": "HumanEval/52", "completion": "return all(x < t for x in l)\n "} +{"task_id": "HumanEval/53", "completion": "return x + y\n "} +{"task_id": "HumanEval/54", "completion": "return set(s0) == set(s1)\n "} +{"task_id": "HumanEval/55", "completion": "if n <= 0:\n return 0\n elif n == 1:\n return 1\n else:\n a, b = 0, 1\n for _ in range(2, n + 1):\n a, b = b, a + b\n return b\n "} +{"task_id": "HumanEval/56", "completion": "balance = 0\n for char in brackets:\n if char == '<':\n balance += 1\n elif char == '>':\n balance -= 1\n if balance < 0:\n return False\n return balance == 0\n "} +{"task_id": "HumanEval/57", "completion": "increasing = True\n decreasing = True\n\n for i in range(1, len(l)):\n if l[i] > l[i - 1]:\n decreasing = False\n elif l[i] < l[i - 1]:\n increasing = False\n\n return increasing or decreasing\n "} +{"task_id": "HumanEval/58", "completion": "return sorted(set(l1) & set(l2))\n "} +{"task_id": "HumanEval/59", "completion": "largest = None\n for i in range(2, int(n**0.5) + 1):\n while n % i == 0:\n largest = i\n n //= i\n if n > 1:\n largest = n\n return largest\n "} +{"task_id": "HumanEval/60", "completion": "return n * (n + 1) // 2\n "} +{"task_id": "HumanEval/61", "completion": " balance = 0\n for char in brackets:\n if char == '(': \n balance += 1\n elif char == ')': \n balance -= 1\n # If balance goes negative, there's a closing bracket without a matching opening bracket\n if balance < 0:\n return False\n # Finally, check if we have a balanced count of opening and closing brackets\n return balance == 0\n "} +{"task_id": "HumanEval/62", "completion": "return [i * coef for i, coef in enumerate(xs)][1:]\n "} +{"task_id": "HumanEval/63", "completion": " if n == 0:\n return 0\n elif n == 1:\n return 0\n elif n == 2:\n return 1\n else:\n a, b, c = 0, 0, 1\n for _ in range(3, n + 1):\n a, b, c = b, c, a + b + c\n return c\n "} +{"task_id": "HumanEval/64", "completion": "count = 0\n vowels = set('aeiouAEIOU')\n \n for char in s:\n if char in vowels:\n count += 1\n \n # Check if the last character is 'y' and includes it if needed\n if s and s[-1].lower() == 'y':\n count += 1\n \n return count\n "} +{"task_id": "HumanEval/65", "completion": "x_str = str(x)\n length = len(x_str)\n if shift >= length:\n return x_str[::-1]\n else:\n return x_str[-shift:] + x_str[:-shift]\n "} +{"task_id": "HumanEval/66", "completion": "total_sum = sum(ord(char) for char in s if char.isupper())\n return total_sum\n "} +{"task_id": "HumanEval/67", "completion": "import re\n apples = int(re.search(r'(\\d+) apples', s).group(1))\n oranges = int(re.search(r'(\\d+) oranges', s).group(1))\n return n - apples - oranges\n "} +{"task_id": "HumanEval/68", "completion": "smallest_even = float('inf')\n smallest_index = -1\n \n for index, value in enumerate(arr):\n if value % 2 == 0 and value < smallest_even:\n smallest_even = value\n smallest_index = index\n \n if smallest_index == -1:\n return []\n \n return [smallest_even, smallest_index]\n "} +{"task_id": "HumanEval/69", "completion": "from collections import Counter\n\n frequency = Counter(lst)\n result = -1\n\n for num in sorted(frequency.keys(), reverse=True):\n if frequency[num] >= num:\n result = num\n break\n \n return result\n "} +{"task_id": "HumanEval/70", "completion": " result = []\n while lst:\n result.append(min(lst)) # Add minimum value\n lst.remove(min(lst))\n if lst:\n result.append(max(lst)) # Add maximum value\n lst.remove(max(lst))\n return result\n "} +{"task_id": "HumanEval/71", "completion": "import math\n\nif a + b > c and a + c > b and b + c > a:\n s = (a + b + c) / 2\n area = math.sqrt(s * (s - a) * (s - b) * (s - c))\n return round(area, 2)\nelse:\n return -1\n "} +{"task_id": "HumanEval/72", "completion": " return q == q[::-1] and sum(q) <= w\n\n "} +{"task_id": "HumanEval/73", "completion": "changes = 0\n n = len(arr)\n for i in range(n // 2):\n if arr[i] != arr[n - 1 - i]:\n changes += 1\n return changes\n "} +{"task_id": "HumanEval/74", "completion": "total1 = sum(len(s) for s in lst1)\n total2 = sum(len(s) for s in lst2)\n \n if total1 < total2:\n return lst1\n else:\n return lst2\n "} +{"task_id": "HumanEval/75", "completion": "from itertools import combinations\nfrom sympy import isprime\n\n primes = [i for i in range(2, 100) if isprime(i)]\n for combo in combinations(primes, 3):\n if combo[0] * combo[1] * combo[2] == a:\n return True\n return False\n "} +{"task_id": "HumanEval/76", "completion": "if n <= 1:\n return x == 1\n power = 0\n while True:\n result = n ** power\n if result == x:\n return True\n elif result > x:\n return False\n power += 1\n "} +{"task_id": "HumanEval/77", "completion": "return round(a ** (1/3)) ** 3 == a\n "} +{"task_id": "HumanEval/78", "completion": "prime_digits = {'2', '3', '5', '7', 'B', 'D'}\n count = 0\n for char in num:\n if char in prime_digits:\n count += 1\n return count\n "} +{"task_id": "HumanEval/79", "completion": "binary = bin(decimal)[2:] # Convert to binary and strip the '0b' prefix\n return f\"db{binary}db\" # Format the string with 'db' at both ends\n "} +{"task_id": "HumanEval/80", "completion": " if len(s) < 3:\n return False\n for i in range(len(s) - 2):\n if len(set(s[i:i+3])) < 3:\n return False\n return True\n "} +{"task_id": "HumanEval/81", "completion": "letter_grades = []\n for gpa in grades:\n if gpa == 4.0:\n letter_grades.append('A+')\n elif gpa > 3.7:\n letter_grades.append('A')\n elif gpa > 3.3:\n letter_grades.append('A-')\n elif gpa > 3.0:\n letter_grades.append('B+')\n elif gpa > 2.7:\n letter_grades.append('B')\n elif gpa > 2.3:\n letter_grades.append('B-')\n elif gpa > 2.0:\n letter_grades.append('C+')\n elif gpa > 1.7:\n letter_grades.append('C')\n elif gpa > 1.3:\n letter_grades.append('C-')\n elif gpa > 1.0:\n letter_grades.append('D+')\n elif gpa > 0.7:\n letter_grades.append('D')\n elif gpa > 0.0:\n letter_grades.append('D-')\n else:\n letter_grades.append('E')\n \n return letter_grades\n "} +{"task_id": "HumanEval/82", "completion": " if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n\nreturn is_prime(len(string))\n "} +{"task_id": "HumanEval/83", "completion": "if n == 1:\n return 1 # only the number '1'\n count_start = 10**(n-1)\n count_end = 9 * 10**(n-2)\n count_both = 10**(n-2)\n return count_start + count_end - count_both\n "} +{"task_id": "HumanEval/84", "completion": "binary_representation = bin(N)[2:] # Convert to binary and remove the '0b' prefix\n digit_sum = sum(int(digit) for digit in binary_representation) # Sum the binary digits\n return bin(digit_sum)[2:] # Convert the sum to binary and remove the '0b' prefix\n "} +{"task_id": "HumanEval/85", "completion": "total = 0\n for i in range(1, len(lst), 2): # start from index 1 and step by 2\n if lst[i] % 2 == 0: # check if the element is even\n total += lst[i]\n return total\n "} +{"task_id": "HumanEval/86", "completion": "words = s.split(' ')\n ordered_words = [''.join(sorted(word)) for word in words]\n return ' '.join(ordered_words)\n "} +{"task_id": "HumanEval/87", "completion": " coordinates = []\n for i, row in enumerate(lst):\n for j, value in enumerate(row):\n if value == x:\n coordinates.append((i, j))\n # Sort first by row (i) and then by column (j) in descending order\n coordinates.sort(key=lambda coord: (coord[0], -coord[1]))\n return coordinates\n "} +{"task_id": "HumanEval/88", "completion": "if not array: # Handle the empty array case\n return []\n \n first_element = array[0]\n last_element = array[-1]\n sum_of_elements = first_element + last_element\n \n # Sort based on the sum being odd or even\n if sum_of_elements % 2 == 0:\n return sorted(array, reverse=True) # Even sum: descending order\n else:\n return sorted(array) # Odd sum: ascending order\n "} +{"task_id": "HumanEval/89", "completion": " encrypted_string = ''\n for char in s:\n if char.isalpha():\n # Shift character by 8 positions (2 multiplied by 4)\n new_char = chr((ord(char) - ord('a') + 8) % 26 + ord('a')) if char.islower() else chr((ord(char) - ord('A') + 8) % 26 + ord('A'))\n encrypted_string += new_char\n return encrypted_string\n "} +{"task_id": "HumanEval/90", "completion": "unique_elements = sorted(set(lst))\n return unique_elements[1] if len(unique_elements) > 1 else None\n "} +{"task_id": "HumanEval/91", "completion": " # Split the string into sentences\n sentences = re.split(r'[.!?]', S)\n # Count sentences that start with the word \"I\"\n count = sum(1 for sentence in sentences if sentence.strip().startswith(\"I\"))\n return count\n "} +{"task_id": "HumanEval/92", "completion": "if all(isinstance(i, int) for i in (x, y, z)): \n return x == y + z or y == x + z or z == x + y\n return False\n "} +{"task_id": "HumanEval/93", "completion": " encoded_message = \"\"\n vowels = {'a': 'c', 'e': 'g', 'i': 'k', 'o': 'q', 'u': 'w',\n 'A': 'C', 'E': 'G', 'I': 'K', 'O': 'Q', 'U': 'W'}\n\n for char in message:\n if char.isalpha():\n # Swap case\n if char in vowels:\n encoded_message += vowels[char] # Replace vowel\n else:\n encoded_message += char.swapcase() # Swap case for consonants\n else:\n encoded_message += char # Keep non-letter characters unchanged\n\n return encoded_message\n "} +{"task_id": "HumanEval/94", "completion": " if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n\nlargest_prime = max((x for x in lst if is_prime(x)), default=None)\n\nif largest_prime is not None:\n sum_of_digits = sum(int(digit) for digit in str(largest_prime))\nelse:\n sum_of_digits = 0 # Or handle the case where there are no primes differently\n\nreturn sum_of_digits\n "} +{"task_id": "HumanEval/95", "completion": "if not dict: # Check for empty dictionary\n return False\n\n keys = list(dict.keys())\n all_lower = all(isinstance(key, str) and key.islower() for key in keys)\n all_upper = all(isinstance(key, str) and key.isupper() for key in keys)\n\n return all_lower or all_upper\n "} +{"task_id": "HumanEval/96", "completion": " if n < 2:\n return []\n primes = []\n for num in range(2, n):\n is_prime = True\n for divisor in range(2, int(num**0.5) + 1):\n if num % divisor == 0:\n is_prime = False\n break\n if is_prime:\n primes.append(num)\n return primes\n "} +{"task_id": "HumanEval/97", "completion": " return (abs(a) % 10) * (abs(b) % 10)\n "} +{"task_id": "HumanEval/98", "completion": "return sum(1 for i in range(0, len(s), 2) if s[i] in 'AEIOU')\n "} +{"task_id": "HumanEval/99", "completion": "value = float(value)\n if value > 0:\n return int(value + 0.5)\n else:\n return int(value - 0.5)\n "} +{"task_id": "HumanEval/100", "completion": "levels = []\n current_stones = n\n for i in range(n):\n levels.append(current_stones)\n if n % 2 == 0: # n is even\n current_stones += 2\n else: # n is odd\n current_stones += 2\n return levels\n "} +{"task_id": "HumanEval/101", "completion": "return [word.strip() for word in s.replace(',', ' ').split() if word]\n "} +{"task_id": "HumanEval/102", "completion": "if x > y:\n return -1\n \n for number in range(y, x - 1, -1):\n if number % 2 == 0:\n return number\n \n return -1\n "} +{"task_id": "HumanEval/103", "completion": "if n > m:\n return -1\n \n total_sum = sum(range(n, m + 1))\n count = m - n + 1\n average = total_sum / count\n rounded_average = round(average)\n \n return bin(rounded_average)\n "} +{"task_id": "HumanEval/104", "completion": "result = []\n for num in x:\n if all(int(digit) % 2 != 0 for digit in str(num)):\n result.append(num)\n return sorted(result)\n "} +{"task_id": "HumanEval/105", "completion": "filtered_arr = [x for x in arr if 1 <= x <= 9]\n sorted_arr = sorted(filtered_arr)\n reversed_arr = sorted_arr[::-1]\n \n num_to_word = {\n 1: \"One\", 2: \"Two\", 3: \"Three\", \n 4: \"Four\", 5: \"Five\", 6: \"Six\", \n 7: \"Seven\", 8: \"Eight\", 9: \"Nine\"\n }\n \n return [num_to_word[num] for num in reversed_arr]\n "} +{"task_id": "HumanEval/106", "completion": "result = []\nfor i in range(1, n + 1):\n if i % 2 == 0:\n # Calculate factorial\n fact = 1\n for j in range(1, i + 1):\n fact *= j\n result.append(fact)\n else:\n # Calculate sum from 1 to i\n sum_odd = sum(range(1, i + 1))\n result.append(sum_odd)\nreturn result\n "} +{"task_id": "HumanEval/107", "completion": "even_count = 0\n odd_count = 0\n \n for i in range(1, n + 1):\n if str(i) == str(i)[::-1]: # Check if the number is a palindrome\n if i % 2 == 0:\n even_count += 1\n else:\n odd_count += 1\n \n return (even_count, odd_count)\n "} +{"task_id": "HumanEval/108", "completion": " return sum(int(d) if n >= 0 else int(d) * (-1 if i == 0 else 1) for i, d in enumerate(str(abs(n))))\n\n return sum(1 for num in arr if digit_sum(num) > 0)\n "} +{"task_id": "HumanEval/109", "completion": "if not arr:\n return True\n\ncount = 0\nn = len(arr)\n\nfor i in range(n):\n if arr[i] > arr[(i + 1) % n]:\n count += 1\n if count > 1:\n return False\n\nreturn True\n "} +{"task_id": "HumanEval/110", "completion": "if any(x % 2 != 0 for x in lst1):\n if any(x % 2 == 0 for x in lst2):\n return \"YES\"\n else:\n return \"NO\"\n return \"YES\"\n "} +{"task_id": "HumanEval/111", "completion": "from collections import defaultdict\n\n if not test:\n return {}\n \n counts = defaultdict(int)\n for letter in test.split():\n counts[letter] += 1\n \n max_count = max(counts.values())\n result = {letter: count for letter, count in counts.items() if count == max_count}\n\n return result\n "} +{"task_id": "HumanEval/112", "completion": "filtered = ''.join([char for char in s if char not in c])\n is_palindrome = filtered == filtered[::-1]\n return (filtered, is_palindrome)\n "} +{"task_id": "HumanEval/113", "completion": "result = []\n for s in lst:\n odd_count = sum(1 for char in s if char in '13579')\n result.append(f\"the number of odd elements {odd_count}n the str{odd_count}ng {odd_count} of the {odd_count}nput.\")\n return result\n "} +{"task_id": "HumanEval/114", "completion": "min_sum = float('inf')\n n = len(nums)\n\n for start in range(n):\n current_sum = 0\n for end in range(start, n):\n current_sum += nums[end]\n min_sum = min(min_sum, current_sum)\n\n return min_sum\n "} +{"task_id": "HumanEval/115", "completion": "total_lowers = 0\n for row in grid:\n water_count = sum(row) # Count number of 1's in the row\n if water_count > 0:\n lowers_for_row = math.ceil(water_count / capacity) # Calculate lowers needed for this row\n total_lowers += lowers_for_row\n return total_lowers\n "} +{"task_id": "HumanEval/116", "completion": "return sorted(arr, key=lambda x: (bin(x).count('1'), x))\n "} +{"task_id": "HumanEval/117", "completion": " consonants = \"bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ\"\n return sum(1 for char in word if char in consonants)\n\n return [word for word in s.split() if count_consonants(word) == n]\n "} +{"task_id": "HumanEval/118", "completion": "vowels = \"aeiouAEIOU\"\n length = len(word)\n \n for i in range(length - 2, 0, -1): # Start from the second last character and go backwards\n if word[i] in vowels and word[i - 1].isalpha() and word[i + 1].isalpha() and word[i - 1] not in vowels and word[i + 1] not in vowels:\n return word[i]\n return \"\"\n "} +{"task_id": "HumanEval/119", "completion": "# Count the parentheses in both strings\nopen_count_1 = lst[0].count('(')\nclose_count_1 = lst[0].count(')')\nopen_count_2 = lst[1].count('(')\nclose_count_2 = lst[1].count(')')\n\n# Check the conditions for both concatenation orders\n # Checking for the first order lst[0] + lst[1]\n net_open = open1 - close1\n net_close = open2 - close2\n return net_open >= 0 and net_open + net_close >= 0\n\ncan_form_good = (is_good(open_count_1, close_count_1, open_count_2, close_count_2) or\n is_good(open_count_2, close_count_2, open_count_1, close_count_1))\n\nreturn 'Yes' if can_form_good else 'No'\n "} +{"task_id": "HumanEval/120", "completion": "arr.sort(reverse=True)\n return sorted(arr[:k])\n "} +{"task_id": "HumanEval/121", "completion": "return sum(lst[i] for i in range(len(lst)) if i % 2 == 0 and lst[i] % 2 != 0)\n "} +{"task_id": "HumanEval/122", "completion": "return sum(x for x in arr[:k] if -99 <= x <= 99)\n "} +{"task_id": "HumanEval/123", "completion": "odd_numbers = []\n while n != 1:\n if n % 2 != 0:\n odd_numbers.append(n)\n n = 3 * n + 1 if n % 2 != 0 else n // 2\n odd_numbers.append(1) # Append 1, since Collatz(1) is [1]\n return sorted(odd_numbers)\n "} +{"task_id": "HumanEval/124", "completion": "if not date:\n return False\n \n parts = date.split('-')\n if len(parts) != 3:\n return False\n \n month, day, year = parts\n if not (month.isdigit() and day.isdigit() and year.isdigit()):\n return False\n \n month = int(month)\n day = int(day)\n year = int(year)\n \n if month < 1 or month > 12:\n return False\n if day < 1:\n return False\n\n if month in [1, 3, 5, 7, 8, 10, 12]:\n if day > 31:\n return False\n elif month in [4, 6, 9, 11]:\n if day > 30:\n return False\n else: # February\n if day > 29:\n return False\n\n return True\n "} +{"task_id": "HumanEval/125", "completion": "if ' ' in txt:\n return txt.split()\n elif ',' in txt:\n return txt.split(',')\n else:\n return sum(1 for char in txt if char.islower() and (ord(char) - ord('a')) % 2 == 1)\n "} +{"task_id": "HumanEval/126", "completion": "if len(lst) <= 1:\n return True\n\n seen = set()\n prev = -1 # Initialize to a value smaller than any possible list element\n\n for num in lst:\n if num in seen or num < prev:\n return False\n seen.add(num)\n prev = num\n\n return True\n "} +{"task_id": "HumanEval/127", "completion": " if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n\n start = max(interval1[0], interval2[0])\n end = min(interval1[1], interval2[1])\n \n if start >= end:\n return \"NO\"\n \n length = end - start\n return \"YES\" if is_prime(length) else \"NO\"\n "} +{"task_id": "HumanEval/128", "completion": "if not arr:\n return None\n\nproduct_of_signs = 1\nsum_of_magnitudes = 0\n\nfor number in arr:\n if number > 0:\n sum_of_magnitudes += number\n elif number < 0:\n sum_of_magnitudes += -number\n product_of_signs *= -1\n else:\n product_of_signs = 0\n\nreturn sum_of_magnitudes * product_of_signs\n "} +{"task_id": "HumanEval/129", "completion": "paths = []\nfor i in range(len(grid)):\n for j in range(len(grid[0])):\n dfs(i, j, [grid[i][j]])\n\n# Find the lexicographically smallest path\nmin_path = min(paths)\nreturn min_path\n "} +{"task_id": "HumanEval/130", "completion": "sequence = []\n\nfor i in range(n + 1):\n if i == 1:\n sequence.append(3)\n elif i % 2 == 0:\n sequence.append(1 + i / 2)\n else:\n tri_i_minus_1 = sequence[i - 1] if i - 1 >= 0 else 0\n tri_i_minus_2 = sequence[i - 2] if i - 2 >= 0 else 0\n tri_i_plus_1 = sequence[i + 1] if i + 1 <= n else 0\n \n sequence.append(tri_i_minus_1 + tri_i_minus_2 + tri_i_plus_1)\n\nreturn sequence\n "} +{"task_id": "HumanEval/131", "completion": "product = 1\n found_odd = False\n \n for digit in str(n):\n if int(digit) % 2 != 0:\n product *= int(digit)\n found_odd = True\n \n return product if found_odd else 0\n "} +{"task_id": "HumanEval/132", "completion": "stack = []\n has_nested = False\n\n for char in string:\n if char == '[':\n stack.append(char)\n if len(stack) > 1: # More than one '[' means potential for nesting\n has_nested = True\n elif char == ']':\n if stack: # Only pop if there's a matching '['\n stack.pop()\n\n return has_nested and not stack # Return True if nested and all brackets are closed\n "} +{"task_id": "HumanEval/133", "completion": "import math\n\nreturn sum(math.ceil(x) ** 2 for x in lst)\n "} +{"task_id": "HumanEval/134", "completion": "if not txt or txt[-1] == ' ':\n return False\n txt = txt.rstrip() # Remove trailing spaces\n return txt[-1].isalpha() and (len(txt) == 1 or txt[-2] == ' ')\n "} +{"task_id": "HumanEval/135", "completion": "largest_index = -1\n for i in range(1, len(arr)):\n if arr[i] < arr[i - 1]:\n largest_index = i\n return largest_index\n "} +{"task_id": "HumanEval/136", "completion": "largest_negative = None\n smallest_positive = None\n \n for num in lst:\n if num < 0:\n if largest_negative is None or num > largest_negative:\n largest_negative = num\n elif num > 0:\n if smallest_positive is None or num < smallest_positive:\n smallest_positive = num\n\n return (largest_negative, smallest_positive)\n "} +{"task_id": "HumanEval/137", "completion": "if isinstance(a, str):\n a = a.replace(',', '.')\n a = float(a)\n if isinstance(b, str):\n b = b.replace(',', '.')\n b = float(b)\n \n if a == b:\n return None\n return a if a > b else b\n "} +{"task_id": "HumanEval/138", "completion": "if n < 8:\n return False\n return n % 2 == 0\n "} +{"task_id": "HumanEval/139", "completion": " result = 1\n for i in range(1, n + 1):\n factorial = 1\n for j in range(1, i + 1):\n factorial *= j\n result *= factorial\n return result\n "} +{"task_id": "HumanEval/140", "completion": " return '-'.join(['_'.join(part.split()) for part in text.split(' ')])\n "} +{"task_id": "HumanEval/141", "completion": "# Check for the number of digits\n digit_count = sum(c.isdigit() for c in file_name)\n if digit_count > 3:\n return 'No'\n\n # Split the file name by dot\n parts = file_name.split('.')\n if len(parts) != 2: # It should have exactly one dot, resulting in two parts\n return 'No'\n\n name, ext = parts\n # Check the first part of the name\n if not name or not name[0].isalpha():\n return 'No'\n\n # Check the extension\n if ext not in ['txt', 'exe', 'dll']:\n return 'No'\n\n return 'Yes'\n "} +{"task_id": "HumanEval/142", "completion": "total_sum = 0\n for index, value in enumerate(lst):\n if index % 3 == 0:\n total_sum += value ** 2\n elif index % 4 == 0:\n total_sum += value ** 3\n else:\n total_sum += value\n return total_sum\n "} +{"task_id": "HumanEval/143", "completion": "result = \" \".join(word for word in sentence.split() if is_prime(len(word)))\n "} +{"task_id": "HumanEval/144", "completion": "from fractions import Fraction\n\n x_fraction = Fraction(x)\n n_fraction = Fraction(n)\n result = x_fraction * n_fraction\n return result.denominator == 1\n "} +{"task_id": "HumanEval/145", "completion": " return sum(int(digit) for digit in str(abs(n)))\n\n return sorted(nums, key=lambda x: (digit_sum(x), nums.index(x)))\n "} +{"task_id": "HumanEval/146", "completion": " count = 0\n for num in nums:\n if num > 10:\n str_num = str(num)\n first_digit = int(str_num[0])\n last_digit = int(str_num[-1])\n if first_digit % 2 != 0 and last_digit % 2 != 0:\n count += 1\n return count\n "} +{"task_id": "HumanEval/147", "completion": "from itertools import combinations\n\n a = [i * i - i + 1 for i in range(1, n + 1)]\n count = 0\n for i, j, k in combinations(range(n), 3):\n if (a[i] + a[j] + a[k]) % 3 == 0:\n count += 1\n return count\n "} +{"task_id": "HumanEval/148", "completion": "planets = [\n \"Mercury\", \"Venus\", \"Earth\", \"Mars\",\n \"Jupiter\", \"Saturn\", \"Uranus\", \"Neptune\"\n ]\n\n if planet1 not in planets or planet2 not in planets:\n return ()\n\n index1 = planets.index(planet1)\n index2 = planets.index(planet2)\n\n start_index, end_index = sorted((index1, index2))\n\n return tuple(planets[start_index + 1:end_index])\n "} +{"task_id": "HumanEval/149", "completion": "filtered_list = [s for s in lst if len(s) % 2 == 0]\nsorted_list = sorted(filtered_list, key=lambda x: (len(x), x))\nreturn sorted_list\n "} +{"task_id": "HumanEval/150", "completion": " if num < 2:\n return False\n for i in range(2, int(num**0.5) + 1):\n if num % i == 0:\n return False\n return True\n\nif is_prime(n):\n return x\nelse:\n return y\n "} +{"task_id": "HumanEval/151", "completion": "if not lst:\n return 0\n return sum(x**2 for x in lst if isinstance(x, int) and x >= 0 and x % 2 != 0)\n "} +{"task_id": "HumanEval/152", "completion": "return [abs(s - g) for s, g in zip(game, guess)]\n "} +{"task_id": "HumanEval/153", "completion": "strongest_extension = \"\"\n max_strength = float('-inf')\n\n for extension in extensions:\n CAP = sum(1 for char in extension if char.isupper())\n SM = sum(1 for char in extension if char.islower())\n strength = CAP - SM\n \n if strength > max_strength:\n max_strength = strength\n strongest_extension = extension\n\n return f\"{class_name}.{strongest_extension}\"\n "} +{"task_id": "HumanEval/154", "completion": "rotations = [b[i:] + b[:i] for i in range(len(b))]\n return any(rotation in a for rotation in rotations)\n "} +{"task_id": "HumanEval/155", "completion": "num = str(abs(num))\n even_count = sum(1 for digit in num if int(digit) % 2 == 0)\n odd_count = len(num) - even_count\n return (even_count, odd_count)\n "} +{"task_id": "HumanEval/156", "completion": "roman_numerals = [\n (1000, 'm'), (900, 'cm'), (500, 'd'), (400, 'cd'),\n (100, 'c'), (90, 'xc'), (50, 'l'), (40, 'xl'),\n (10, 'x'), (9, 'ix'), (5, 'v'), (4, 'iv'),\n (1, 'i')\n ]\n\n result = []\n for value, symbol in roman_numerals:\n while number >= value:\n result.append(symbol)\n number -= value\n return ''.join(result)\n "} +{"task_id": "HumanEval/157", "completion": "sides = sorted([a, b, c])\n return sides[0]**2 + sides[1]**2 == sides[2]**2\n "} +{"task_id": "HumanEval/158", "completion": "unique_counts = {word: len(set(word)) for word in words}\n max_unique = max(unique_counts.values(), default=0)\n candidates = [word for word, count in unique_counts.items() if count == max_unique]\n return min(candidates) if candidates else \"\"\n "} +{"task_id": "HumanEval/159", "completion": "total_eaten = number + min(need, remaining)\n remaining_after_eat = remaining - min(need, remaining)\n return [total_eaten, remaining_after_eat]\n "} +{"task_id": "HumanEval/160", "completion": "expression = str(operand[0])\n for op, num in zip(operator, operand[1:]):\n expression += f\" {op} {num}\"\n return eval(expression)\n "} +{"task_id": "HumanEval/161", "completion": "if any(c.isalpha() for c in s): # Check if there's at least one letter\n return ''.join(c.upper() if c.islower() else c.lower() for c in s)\n else: # If there are no letters, reverse the string\n return s[::-1]\n "} +{"task_id": "HumanEval/162", "completion": "import hashlib\n\n if text == \"\":\n return None\n return hashlib.md5(text.encode()).hexdigest()\n "} +{"task_id": "HumanEval/163", "completion": "start = min(a, b)\n end = max(a, b)\n return sorted([i for i in range(start, end + 1) if i % 2 == 0])\n "} diff --git a/experiment/humaneval/interpreter_prediction.jsonl_results.jsonl b/experiment/humaneval/interpreter_prediction.jsonl_results.jsonl new file mode 100644 index 000000000..b52ecada4 --- /dev/null +++ b/experiment/humaneval/interpreter_prediction.jsonl_results.jsonl @@ -0,0 +1,164 @@ +{"task_id": "HumanEval/0", "completion": "for i in range(len(numbers)):\n for j in range(i + 1, len(numbers)):\n if abs(numbers[i] - numbers[j]) < threshold:\n return True\n return False\n", "result": "failed: unindent does not match any outer indentation level (, line 16)", "passed": false} +{"task_id": "HumanEval/1", "completion": "def separate_paren_groups(paren_string: str) -> List[str]:\n paren_string = paren_string.replace(\" \", \"\") # Step 1: Remove spaces\n result = []\n stack = []\n current_group = []\n\n for char in paren_string:\n if char == '(':\n if not stack: # Starting a new group\n current_group = [] # Reset current group\n stack.append(char)\n current_group.append(char) # Add to current group\n elif char == ')':\n stack.pop()\n current_group.append(char) # Add to current group\n if not stack: # If stack is empty, a complete group is found\n result.append(''.join(current_group)) # Add to result\n\n return result\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/2", "completion": "def truncate_number(number: float) -> float:\n return number - int(number)\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/3", "completion": "def below_zero(operations: List[int]) -> bool:\n balance = 0\n for operation in operations:\n balance += operation\n if balance < 0:\n return True\n return False\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/4", "completion": "mean_value = sum(numbers) / len(numbers) # Calculate mean\ndeviations = [abs(x - mean_value) for x in numbers] # Calculate absolute differences\nreturn sum(deviations) / len(deviations) # Calculate and return MAD\n", "result": "failed: 'return' outside function (, line 15)", "passed": false} +{"task_id": "HumanEval/5", "completion": "def intersperse(numbers: List[int], delimeter: int) -> List[int]:\n if not numbers:\n return []\n \n result = []\n for i in range(len(numbers)):\n result.append(numbers[i])\n if i < len(numbers) - 1: # Don't add delimeter after the last element\n result.append(delimeter)\n \n return result\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/6", "completion": "def parse_nested_parens(paren_string: str) -> List[int]:\n depths = []\n groups = paren_string.split()\n\n for group in groups:\n max_depth = 0\n current_depth = 0\n \n for char in group:\n if char == '(':\n current_depth += 1\n max_depth = max(max_depth, current_depth)\n elif char == ')':\n current_depth -= 1\n \n depths.append(max_depth)\n\n return depths\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/7", "completion": "return [s for s in strings if substring in s]\n", "result": "failed: 'return' outside function (, line 11)", "passed": false} +{"task_id": "HumanEval/8", "completion": "def sum_product(numbers: List[int]) -> Tuple[int, int]:\n total_sum = sum(numbers)\n total_product = 1\n for number in numbers:\n total_product *= number\n return total_sum, total_product\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/9", "completion": "def rolling_max(numbers: List[int]) -> List[int]:\n max_so_far = float('-inf')\n rolling_max_list = []\n\n for number in numbers:\n if number > max_so_far:\n max_so_far = number\n rolling_max_list.append(max_so_far)\n\n return rolling_max_list\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/10", "completion": "def make_palindrome(string: str) -> str:\n def is_palindrome(s: str) -> bool:\n return s == s[::-1]\n\n for i in range(len(string)):\n if is_palindrome(string[i:]):\n return string + string[:i][::-1]\n \n return string\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/11", "completion": "result = ''.join(str(int(x) ^ int(y)) for x, y in zip(a, b))\n", "result": "failed: name 'a' is not defined", "passed": false} +{"task_id": "HumanEval/12", "completion": "def longest(strings: List[str]) -> Optional[str]:\n if not strings:\n return None\n longest_string = \"\"\n for string in strings:\n if len(string) > len(longest_string):\n longest_string = string\n return longest_string\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/13", "completion": "def greatest_common_divisor(a: int, b: int) -> int:\n while b:\n a, b = b, a % b\n return a\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/14", "completion": "return [string[:i] for i in range(1, len(string) + 1)]\n", "result": "failed: 'return' outside function (, line 9)", "passed": false} +{"task_id": "HumanEval/15", "completion": "return ' '.join(str(i) for i in range(n + 1))\n", "result": "failed: 'return' outside function (, line 10)", "passed": false} +{"task_id": "HumanEval/16", "completion": "return len(set(string.lower()))\n", "result": "failed: 'return' outside function (, line 10)", "passed": false} +{"task_id": "HumanEval/17", "completion": "def parse_music(music_string: str) -> List[int]:\n note_duration_map = {\n 'o': 4,\n 'o|': 2,\n '.|': 1\n }\n \n notes = music_string.split()\n durations = [note_duration_map[note] for note in notes]\n \n return durations\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/18", "completion": "def how_many_times(string: str, substring: str) -> int:\n count = 0\n start = 0\n\n while True:\n start = string.find(substring, start)\n if start == -1:\n break\n count += 1\n start += 1 # Move to the next character to allow for overlapping\n\n return count\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/19", "completion": "def sort_numbers(numbers: str) -> str:\n number_map = {\n 'zero': 0,\n 'one': 1,\n 'two': 2,\n 'three': 3,\n 'four': 4,\n 'five': 5,\n 'six': 6,\n 'seven': 7,\n 'eight': 8,\n 'nine': 9\n }\n \n words = numbers.split()\n sorted_numbers = sorted(words, key=lambda x: number_map[x])\n return ' '.join(sorted_numbers)\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/20", "completion": "def find_closest_elements(numbers: List[float]) -> Tuple[float, float]:\n numbers.sort()\n closest_pair = (numbers[0], numbers[1])\n min_diff = abs(numbers[1] - numbers[0])\n \n for i in range(1, len(numbers) - 1):\n diff = abs(numbers[i + 1] - numbers[i])\n if diff < min_diff:\n min_diff = diff\n closest_pair = (numbers[i], numbers[i + 1])\n \n return closest_pair\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/21", "completion": "return [(num - min_val) / (max_val - min_val) for num in numbers]\n", "result": "failed: 'return' outside function (, line 10)", "passed": false} +{"task_id": "HumanEval/22", "completion": "return [value for value in values if isinstance(value, int)]\n", "result": "failed: 'return' outside function (, line 11)", "passed": false} +{"task_id": "HumanEval/23", "completion": "return len(string)\n", "result": "failed: 'return' outside function (, line 10)", "passed": false} +{"task_id": "HumanEval/24", "completion": "for i in range(n - 1, 0, -1):\n if n % i == 0:\n return i\n", "result": "failed: 'return' outside function (, line 10)", "passed": false} +{"task_id": "HumanEval/25", "completion": "def factorize(n: int) -> List[int]:\n factors = []\n while n % 2 == 0:\n factors.append(2)\n n //= 2\n for i in range(3, int(n**0.5) + 1, 2):\n while n % i == 0:\n factors.append(i)\n n //= i\n if n > 2:\n factors.append(n)\n return factors\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/26", "completion": "def remove_duplicates(numbers: List[int]) -> List[int]:\n counts = {}\n for number in numbers:\n counts[number] = counts.get(number, 0) + 1\n \n return [number for number in numbers if counts[number] == 1]\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/27", "completion": "return string.swapcase()\n", "result": "failed: 'return' outside function (, line 8)", "passed": false} +{"task_id": "HumanEval/28", "completion": "def concatenate(strings: List[str]) -> str:\n return ''.join(strings)\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/29", "completion": "def filter_by_prefix(strings: List[str], prefix: str) -> List[str]:\n return [s for s in strings if s.startswith(prefix)]\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/30", "completion": "def get_positive(l: list):\n return [num for num in l if num > 0]\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/31", "completion": "def is_prime(n):\n if n < 2:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/32", "completion": "def find_zero(xs: list):\n \"\"\" xs are coefficients of a polynomial. \n find_zero finds x such that poly(x) = 0.\n \"\"\"\n # Contains the polynomial function\n def poly_derivative(xs, x):\n \"\"\" Evaluates the derivative of polynomial with coefficients xs at point x. \"\"\"\n return sum([i * coeff * math.pow(x, i - 1) for i, coeff in enumerate(xs) if i > 0])\n\n # Starting guess can be 0\n x0 = 0.0\n tolerance = 1e-7\n max_iterations = 1000\n for _ in range(max_iterations):\n fx = poly(xs, x0)\n dfx = poly_derivative(xs, x0)\n \n if dfx == 0: # Prevent division by zero\n break\n \n x1 = x0 - fx / dfx\n if abs(x1 - x0) < tolerance: # Check for convergence\n return x1\n x0 = x1\n \n return x0 # Return the last approximation\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/33", "completion": "def sort_third(l: list):\n sorted_third = sorted(l[i] for i in range(len(l)) if i % 3 == 0)\n \n result = l[:]\n j = 0\n for i in range(len(l)):\n if i % 3 == 0:\n result[i] = sorted_third[j]\n j += 1\n\n return result\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/34", "completion": "return sorted(set(l))\n", "result": "failed: 'return' outside function (, line 8)", "passed": false} +{"task_id": "HumanEval/35", "completion": "def max_element(l: list):\n return max(l)\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/36", "completion": "count = 0\nfor i in range(n):\n if i % 11 == 0 or i % 13 == 0:\n count += str(i).count('7')\nreturn count\n", "result": "failed: 'return' outside function (, line 16)", "passed": false} +{"task_id": "HumanEval/37", "completion": "def sort_even(l: list):\n even_indices = sorted(l[i] for i in range(0, len(l), 2))\n result = []\n even_index = 0\n for i in range(len(l)):\n if i % 2 == 0:\n result.append(even_indices[even_index])\n even_index += 1\n else:\n result.append(l[i])\n return result\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/38", "completion": "groups = [s[(3 * i):min((3 * i + 3), len(s))] for i in range((len(s) + 2) // 3)]\n groups = [(group[-1] + group[:-1]) if len(group) == 3 else group for group in groups]\n return \"\".join(groups)\n", "result": "failed: unexpected indent (, line 19)", "passed": false} +{"task_id": "HumanEval/39", "completion": "def is_prime(num):\n if num < 2:\n return False\n for i in range(2, int(num**0.5) + 1):\n if num % i == 0:\n return False\n return True\n\ndef prime_fib(n: int):\n fib1, fib2 = 0, 1\n prime_fib_count = 0\n current_prime_fib = None\n\n while prime_fib_count < n:\n fib1, fib2 = fib2, fib1 + fib2\n if is_prime(fib2):\n prime_fib_count += 1\n current_prime_fib = fib2\n\n return current_prime_fib\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/40", "completion": "def triples_sum_to_zero(l):\n n = len(l)\n for i in range(n):\n s = set()\n current_sum = -l[i]\n for j in range(i + 1, n):\n if (current_sum - l[j]) in s:\n return True\n s.add(l[j])\n return False\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/41", "completion": "def car_race_collision(n: int) -> int:\n return n * n\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/42", "completion": "def incr_list(l):\n return [x + 1 for x in l]\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/43", "completion": "def pairs_sum_to_zero(l):\n seen = set()\n for num in l:\n if -num in seen:\n return True\n seen.add(num)\n return False\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/44", "completion": "result = \"\"\n while x > 0:\n remainder = x % base\n result = str(remainder) + result # Prepend remainder to the result\n x //= base # Divide x by base\n return result if result else \"0\" # Handle case where x is 0\n", "result": "failed: unexpected indent (, line 15)", "passed": false} +{"task_id": "HumanEval/45", "completion": "def triangle_area(a, h):\n return 0.5 * a * h\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/46", "completion": "def fib4(n: int) -> int:\n if n == 0:\n return 0\n elif n == 1:\n return 0\n elif n == 2:\n return 2\n elif n == 3:\n return 0\n\n fib_sequence = [0, 0, 2, 0]\n for i in range(4, n + 1):\n next_value = fib_sequence[-1] + fib_sequence[-2] + fib_sequence[-3] + fib_sequence[-4]\n fib_sequence.append(next_value)\n\n return fib_sequence[n]\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/47", "completion": "l.sort()\n n = len(l)\n if n % 2 == 1: # odd length\n return l[n // 2]\n else: # even length\n return (l[n // 2 - 1] + l[n // 2]) / 2\n", "result": "failed: unexpected indent (, line 11)", "passed": false} +{"task_id": "HumanEval/48", "completion": "return text == text[::-1]\n", "result": "failed: 'return' outside function (, line 15)", "passed": false} +{"task_id": "HumanEval/49", "completion": "return pow(2, n, p)\n", "result": "failed: 'return' outside function (, line 16)", "passed": false} +{"task_id": "HumanEval/50", "completion": "def decode_shift(s: str):\n return \"\".join([chr(((ord(ch) - 5 - ord(\"a\")) % 26) + ord(\"a\")) for ch in s])\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/51", "completion": "def remove_vowels(text):\n vowels = \"aeiouAEIOU\"\n return ''.join([char for char in text if char not in vowels])\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/52", "completion": "for number in l:\n if number >= t:\n return False\nreturn True\n", "result": "failed: 'return' outside function (, line 12)", "passed": false} +{"task_id": "HumanEval/53", "completion": "return x + y\n", "result": "failed: 'return' outside function (, line 10)", "passed": false} +{"task_id": "HumanEval/54", "completion": "return set(s0) == set(s1)\n", "result": "failed: 'return' outside function (, line 19)", "passed": false} +{"task_id": "HumanEval/55", "completion": "if n == 1 or n == 2:\n return 1\n a, b = 1, 1\n for _ in range(3, n + 1):\n a, b = b, a + b\n return b\n", "result": "failed: unindent does not match any outer indentation level (, line 14)", "passed": false} +{"task_id": "HumanEval/56", "completion": "def correct_bracketing(brackets: str):\n count = 0\n for char in brackets:\n if char == \"<\":\n count += 1\n elif char == \">\":\n count -= 1\n if count < 0:\n return False\n return count == 0\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/57", "completion": "def monotonic(l: list):\n if len(l) <= 1:\n return True\n\n increasing = decreasing = True\n\n for i in range(1, len(l)):\n if l[i] > l[i - 1]:\n decreasing = False\n elif l[i] < l[i - 1]:\n increasing = False\n\n return increasing or decreasing\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/58", "completion": "def common(l1: list, l2: list):\n return sorted(set(l1) & set(l2))\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/59", "completion": "def largest_prime_factor(n):\n largest_factor = 1\n # Check for number of 2s that divide n\n while n % 2 == 0:\n largest_factor = 2\n n //= 2\n \n # n must be odd at this point, thus check for odd factors from 3\n for i in range(3, int(n**0.5) + 1, 2):\n while n % i == 0:\n largest_factor = i\n n //= i\n \n # This condition is to check if n is a prime number\n # greater than 2\n if n > 2:\n largest_factor = n\n \n return largest_factor\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/60", "completion": "def sum_to_n(n: int):\n return n * (n + 1) // 2\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/61", "completion": "def correct_bracketing(brackets: str) -> bool:\n counter = 0\n for char in brackets:\n if char == '(':\n counter += 1\n elif char == ')':\n counter -= 1\n if counter < 0:\n return False\n return counter == 0\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/62", "completion": "def derivative(xs):\n return [i * xs[i] for i in range(1, len(xs))]\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/63", "completion": "def fibfib(n: int, memo={0: 0, 1: 0, 2: 1}):\n if n in memo:\n return memo[n]\n memo[n] = fibfib(n-1, memo) + fibfib(n-2, memo) + fibfib(n-3, memo)\n return memo[n]\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/64", "completion": "def vowels_count(s):\n count = 0\n vowels = 'aeiou'\n \n for i, char in enumerate(s.lower()):\n if char in vowels or (char == 'y' and i == len(s) - 1):\n count += 1\n \n return count\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/65", "completion": "def circular_shift(x, shift):\n s = str(x)\n length = len(s)\n \n if shift > length:\n return s[::-1]\n \n shift = shift % length\n return s[-shift:] + s[:-shift]\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/66", "completion": "def digitSum(s):\n return sum(ord(char) for char in s if char.isupper())\n ", "result": "passed", "passed": true} +{"task_id": "HumanEval/67", "completion": "def fruit_distribution(s, n):\n apples = int(s.split()[0]) \n oranges = int(s.split()[3]) \n \n mangoes = n - apples - oranges\n return mangoes\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/68", "completion": "def pluck(arr):\n smallest_even = float('inf')\n smallest_index = -1\n \n for index, value in enumerate(arr):\n if value % 2 == 0: # Check if the value is even\n if value < smallest_even: # Check if it's the smallest even value\n smallest_even = value\n smallest_index = index\n\n if smallest_index == -1: # No even numbers found\n return []\n \n return [smallest_even, smallest_index]\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/69", "completion": "def search(lst):\n frequency = {}\n \n # Count frequency of each number\n for num in lst:\n if num in frequency:\n frequency[num] += 1\n else:\n frequency[num] = 1\n\n # Check for the greatest integer that meets the condition\n for num in sorted(frequency.keys(), reverse=True):\n if frequency[num] >= num:\n return num\n \n return -1\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/70", "completion": "def strange_sort_list(lst):\n lst.sort()\n result = []\n min_ptr, max_ptr = 0, len(lst) - 1\n \n while min_ptr <= max_ptr:\n if min_ptr == max_ptr:\n result.append(lst[min_ptr])\n else:\n result.append(lst[min_ptr])\n result.append(lst[max_ptr])\n \n min_ptr += 1\n max_ptr -= 1\n \n return result\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/71", "completion": "def triangle_area(a, b, c):\n if a + b > c and a + c > b and b + c > a: # Check validity\n s = (a + b + c) / 2 # Semi-perimeter\n area = (s * (s - a) * (s - b) * (s - c)) ** 0.5 # Heron's formula\n return round(area, 2) # Return area rounded to 2 decimal points\n return -1 # Not a valid triangle\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/72", "completion": "def will_it_fly(q, w):\n return q == q[::-1] and sum(q) <= w\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/73", "completion": "def smallest_change(arr):\n changes = 0\n n = len(arr)\n \n for i in range(n // 2):\n if arr[i] != arr[n - 1 - i]:\n changes += 1\n \n return changes\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/74", "completion": "def total_match(lst1, lst2):\n total_chars_lst1 = sum(len(s) for s in lst1)\n total_chars_lst2 = sum(len(s) for s in lst2)\n\n if total_chars_lst1 < total_chars_lst2:\n return lst1\n elif total_chars_lst1 > total_chars_lst2:\n return lst2\n else:\n return lst1\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/75", "completion": "def is_multiply_prime(a):\n primes = [prime(i) for i in range(1, 30) if prime(i) < 100]\n for combo in combinations(primes, 3):\n if combo[0] * combo[1] * combo[2] == a:\n return True\n return False\n", "result": "failed: name 'prime' is not defined", "passed": false} +{"task_id": "HumanEval/76", "completion": "def is_simple_power(x, n):\n if n <= 1:\n return x == n\n power = 1\n while power < x:\n power *= n\n return power == x\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/77", "completion": "return round(abs(a) ** (1/3)) ** 3 == abs(a)\n", "result": "failed: 'return' outside function (, line 15)", "passed": false} +{"task_id": "HumanEval/78", "completion": "prime_hex_digits = {'2', '3', '5', '7', 'B', 'D'}\ncount = 0\n\nfor digit in num:\n if digit in prime_hex_digits:\n count += 1\n\nreturn count\n", "result": "failed: 'return' outside function (, line 27)", "passed": false} +{"task_id": "HumanEval/79", "completion": "def decimal_to_binary(decimal):\n return 'db' + bin(decimal)[2:] + 'db'\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/80", "completion": "def is_happy(s):\n if len(s) < 3:\n return False\n for i in range(len(s) - 2):\n if len(set(s[i:i + 3])) < 3:\n return False\n return True\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/81", "completion": "def numerical_letter_grade(grades):\n letter_grades = []\n for gpa in grades:\n if gpa == 4.0:\n letter_grades.append('A+')\n elif gpa > 3.7:\n letter_grades.append('A')\n elif gpa > 3.3:\n letter_grades.append('A-')\n elif gpa > 3.0:\n letter_grades.append('B+')\n elif gpa > 2.7:\n letter_grades.append('B')\n elif gpa > 2.3:\n letter_grades.append('B-')\n elif gpa > 2.0:\n letter_grades.append('C+')\n elif gpa > 1.7:\n letter_grades.append('C')\n elif gpa > 1.3:\n letter_grades.append('C-')\n elif gpa > 1.0:\n letter_grades.append('D+')\n elif gpa > 0.7:\n letter_grades.append('D')\n elif gpa > 0.0:\n letter_grades.append('D-')\n else:\n letter_grades.append('E')\n return letter_grades\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/82", "completion": "def prime_length(string):\n def is_prime(n):\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n \n length = len(string)\n return is_prime(length)\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/83", "completion": "def starts_one_ends(n):\n if n <= 0:\n return 0\n # Numbers starting with 1\n start_with_1 = 10**(n-1) # 1 followed by (n-1) zeros\n # Numbers ending with 1\n end_with_1 = 10**(n-1)\n\n # Counting overlaps (i.e., numbers that both start and end with 1)\n # These are of the form 1...1, and there are (n-2) digits in between\n overlap_count = 10**(n-2) if n > 1 else 1\n\n return start_with_1 + end_with_1 - overlap_count\n ", "result": "failed: ", "passed": false} +{"task_id": "HumanEval/84", "completion": "def solve(N):\n if not (0 <= N <= 10000):\n raise ValueError(\"N must be between 0 and 10000\")\n\n digit_sum = sum(int(digit) for digit in str(N))\n return bin(digit_sum)[2:]\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/85", "completion": "def add(lst):\n total = 0\n for index, value in enumerate(lst):\n if index % 2 != 0 and value % 2 == 0:\n total += value\n return total\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/86", "completion": "def anti_shuffle(s):\n result = []\n for word in s.split(' '):\n sorted_word = ''.join(sorted(word))\n result.append(sorted_word)\n return ' '.join(result)\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/87", "completion": "coordinates = []\n\nfor row_index, row in enumerate(lst):\n for col_index, value in enumerate(row):\n if value == x:\n coordinates.append((row_index, col_index))\n\ncoordinates.sort(key=lambda coord: (coord[0], -coord[1]))\n\nreturn coordinates\n", "result": "failed: 'return' outside function (, line 31)", "passed": false} +{"task_id": "HumanEval/88", "completion": "def sort_array(array):\n sum_first_last = array[0] + array[-1] if array else 0\n return sorted(array) if sum_first_last % 2 != 0 else sorted(array, reverse=True)\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/89", "completion": "def encrypt(s):\n result = \"\"\n for char in s:\n if 'a' <= char <= 'z': # Check if char is a lowercase letter\n new_char = chr((ord(char) - ord('a') + 4) % 26 + ord('a'))\n result += new_char\n return result\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/90", "completion": "def next_smallest(lst):\n if not lst:\n return None\n unique_elements = list(set(lst))\n unique_elements.sort()\n if len(unique_elements) < 2:\n return None\n return unique_elements[1]\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/91", "completion": "sentences = [s.strip() for s in re.split(r'[.!?]', S) if s] # Split into sentences\nreturn sum(1 for sentence in sentences if sentence.startswith(\"I\")) # Count \"I\"-starting sentences\n", "result": "failed: 'return' outside function (, line 15)", "passed": false} +{"task_id": "HumanEval/92", "completion": "def any_int(x, y, z):\n return all(isinstance(i, int) for i in (x, y, z)) and (\n x == y + z or y == x + z or z == x + y\n )\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/93", "completion": "def encode(message):\n vowels = {'a': 'c', 'e': 'g', 'i': 'k', 'o': 'q', 'u': 'w',\n 'A': 'C', 'E': 'G', 'I': 'K', 'O': 'Q', 'U': 'W'}\n \n result = []\n for char in message:\n if char in vowels:\n result.append(vowels[char])\n elif char.isalpha():\n result.append(char.swapcase())\n else:\n result.append(char)\n \n return ''.join(result)\n", "result": "failed: This prints if this assert fails 1 (good for debugging!)", "passed": false} +{"task_id": "HumanEval/94", "completion": "def skjkasdkd(lst):\n def is_prime(n):\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n \n largest_prime = None\n \n for num in lst:\n if is_prime(num):\n if largest_prime is None or num > largest_prime:\n largest_prime = num\n \n if largest_prime is None:\n return 0 # or some other default value if there's no prime\n \n return sum(int(digit) for digit in str(largest_prime))\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/95", "completion": "def check_dict_case(d):\n if not d: # Check if the dictionary is empty\n return False\n \n keys = d.keys() # Get all keys from the dictionary\n all_lower = all(isinstance(k, str) and k.islower() for k in keys) # Check if all keys are lower case\n all_upper = all(isinstance(k, str) and k.isupper() for k in keys) # Check if all keys are upper case\n \n return all_lower or all_upper # Return True if either condition is met\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/96", "completion": "def is_prime(num):\n if num < 2:\n return False\n for i in range(2, int(num**0.5) + 1):\n if num % i == 0:\n return False\n return True\n\ndef count_up_to(n):\n return [i for i in range(2, n) if is_prime(i)]\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/97", "completion": "def multiply(a, b):\n # Get the unit digit of each number\n unit_digit_a = abs(a) % 10\n unit_digit_b = abs(b) % 10\n # Return the product of the unit digits\n return unit_digit_a * unit_digit_b\n ", "result": "passed", "passed": true} +{"task_id": "HumanEval/98", "completion": "def count_upper(s):\n count = 0\n for i in range(0, len(s), 2):\n if s[i] in 'AEIOU':\n count += 1\n return count\n ", "result": "passed", "passed": true} +{"task_id": "HumanEval/99", "completion": "number = float(value)\n floor_value = int(number) # Get the floor value of the number\n ceil_value = floor_value + 1 # Get the ceiling value\n \n if number - floor_value < 0.5:\n return floor_value\n elif number - floor_value > 0.5:\n return ceil_value\n else: # number - floor_value == 0.5\n return ceil_value if number > 0 else floor_value\n", "result": "failed: unexpected indent (, line 21)", "passed": false} +{"task_id": "HumanEval/100", "completion": "def make_a_pile(n):\n stones = []\n current_stones = n\n \n for i in range(n):\n stones.append(current_stones)\n if current_stones % 2 == 0: # current_stones is even\n current_stones += 2 # next level will have the next even number\n else:\n current_stones += 2 # next level will have the next odd number\n \n return stones\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/101", "completion": "import re\n\ndef words_string(s):\n return re.split(r'[ ,]+', s)\n", "result": "failed: ", "passed": false} +{"task_id": "HumanEval/102", "completion": "def choose_num(x, y):\n lower = min(x, y)\n upper = max(x, y)\n \n for num in range(upper, lower - 1, -1):\n if num % 2 == 0:\n return num\n return -1\n", "result": "failed: ", "passed": false} +{"task_id": "HumanEval/103", "completion": "def rounded_avg(n, m):\n if n > m:\n return -1\n avg = round((n + m) / 2)\n return bin(avg)\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/104", "completion": "result = []\nfor num in x:\n if all(int(digit) % 2 != 0 for digit in str(num)): # Check if all digits are odd\n result.append(num)\nreturn sorted(result)\n", "result": "failed: 'return' outside function (, line 18)", "passed": false} +{"task_id": "HumanEval/105", "completion": "def by_length(arr):\n filtered = [x for x in arr if 1 <= x <= 9] # Step 1: Filter numbers\n sorted_arr = sorted(filtered) # Step 2: Sort the array\n reversed_arr = sorted_arr[::-1] # Step 3: Reverse the array\n\n # Step 4: Map integers to their names\n number_names = [\"One\", \"Two\", \"Three\", \"Four\", \"Five\", \"Six\", \"Seven\", \"Eight\", \"Nine\"]\n result = [number_names[x - 1] for x in reversed_arr] # Step 5: Replace with names\n return result\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/106", "completion": "result = []\nfor i in range(1, n + 1):\n if i % 2 == 0: # i is even\n factorial = 1\n for j in range(1, i + 1):\n factorial *= j\n result.append(factorial)\n else: # i is odd\n sum_odd = sum(range(1, i + 1))\n result.append(sum_odd)\nreturn result\n", "result": "failed: 'return' outside function (, line 21)", "passed": false} +{"task_id": "HumanEval/107", "completion": "def even_odd_palindrome(n):\n def is_palindrome(num):\n return str(num) == str(num)[::-1]\n \n odd_count = 0\n even_count = 0\n \n for i in range(1, n + 1):\n if is_palindrome(i):\n if i % 2 == 0:\n even_count += 1\n else:\n odd_count += 1\n \n return (even_count, odd_count)\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/108", "completion": "def count_nums(arr):\n count = 0\n for num in arr:\n digit_sum = sum(int(digit) if num >= 0 else -int(digit) for digit in str(abs(num)))\n if digit_sum > 0:\n count += 1\n return count\n", "result": "failed: ", "passed": false} +{"task_id": "HumanEval/109", "completion": "def move_one_ball(arr):\n if not arr:\n return True\n\n descents = 0\n n = len(arr)\n\n for i in range(n):\n if arr[i] > arr[(i + 1) % n]: # Use modulo to wrap around\n descents += 1\n\n return descents <= 1\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/110", "completion": "def exchange(lst1, lst2):\n odd_count = sum(1 for x in lst1 if x % 2 != 0)\n even_count_in_lst2 = sum(1 for x in lst2 if x % 2 == 0)\n if odd_count <= even_count_in_lst2:\n return \"YES\"\n else:\n return \"NO\"\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/111", "completion": "def histogram(test):\n counts = {}\n \n # Split the input string into letters and count occurrences\n for letter in test.split():\n counts[letter] = counts.get(letter, 0) + 1\n \n if not counts:\n return {}\n \n # Find the maximum count\n max_count = max(counts.values())\n \n # Gather all letters with the maximum count\n result = {letter: count for letter, count in counts.items() if count == max_count}\n \n return result\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/112", "completion": "def reverse_delete(s, c):\n result = ''.join(char for char in s if char not in c) # Step 1: Remove characters\n is_palindrome = result == result[::-1] # Step 2: Check for palindrome\n return result, is_palindrome # Step 3: Return result\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/113", "completion": "def odd_count(lst):\n result = []\n for s in lst:\n odd_count = sum(1 for char in s if char in '13579')\n result.append(f\"the number of odd elements {odd_count}n the str{odd_count}ng {odd_count} of the {odd_count}nput.\")\n return result\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/114", "completion": "def minSubArraySum(nums):\n min_sum = float('inf')\n current_sum = 0\n\n for num in nums:\n current_sum += num\n if current_sum < min_sum:\n min_sum = current_sum\n if current_sum > 0:\n current_sum = 0\n\n return min_sum\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/115", "completion": "def max_fill(grid, capacity):\n total_water = 0\n \n # Count total water in the grid\n for row in grid:\n total_water += sum(row)\n \n # Calculate number of times to lower buckets\n return math.ceil(total_water / capacity)\n", "result": "failed: name 'math' is not defined", "passed": false} +{"task_id": "HumanEval/116", "completion": "def sort_array(arr):\n arr.sort(key=lambda x: (bin(x).count('1'), x))\n return arr\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/117", "completion": "def select_words(s, n):\n if not s:\n return []\n \n def count_consonants(word):\n consonants = \"bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ\"\n return sum(1 for char in word if char in consonants)\n \n words = s.split()\n result = [word for word in words if count_consonants(word) == n]\n \n return result\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/118", "completion": "def get_closest_vowel(word):\n vowels = 'aeiouAEIOU'\n last_consonants = []\n \n # Traverse the string from right to left\n for char in reversed(word):\n if char in vowels:\n # Check for vowels between two consonants\n if len(last_consonants) == 2:\n return char\n elif char.isalpha(): # It is a consonant\n last_consonants.append(char)\n # Keep only the last two consonants\n if len(last_consonants) > 2:\n last_consonants.pop(0)\n\n return \"\"\n", "result": "failed: ", "passed": false} +{"task_id": "HumanEval/119", "completion": "def match_parens(lst):\n s1, s2 = lst\n\n def is_balanced(s1, s2):\n count = 0\n for char in s1 + s2:\n if char == '(':\n count += 1\n else:\n count -= 1\n if count < 0:\n return False\n return count == 0\n\n return 'Yes' if is_balanced(s1, s2) or is_balanced(s2, s1) else 'No'\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/120", "completion": "def maximum(arr, k):\n return sorted(sorted(arr)[-k:])\n", "result": "failed: ", "passed": false} +{"task_id": "HumanEval/121", "completion": "total_sum = sum(lst[i] for i in range(len(lst)) if i % 2 == 0 and lst[i] % 2 != 0)\nreturn total_sum\n", "result": "failed: 'return' outside function (, line 12)", "passed": false} +{"task_id": "HumanEval/122", "completion": "def add_elements(arr, k):\n return sum(x for x in arr[:k] if -10 < x < 100)\n ", "result": "passed", "passed": true} +{"task_id": "HumanEval/123", "completion": "def get_odd_collatz(n):\n odd_numbers = []\n \n while n != 1:\n if n % 2 != 0: # n is odd\n odd_numbers.append(n)\n n = n // 2 if n % 2 == 0 else 3 * n + 1\n \n odd_numbers.append(1) # Append 1 as it's also considered odd\n return sorted(odd_numbers)\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/124", "completion": "def valid_date(date):\n if not date:\n return False\n \n if date.count('-') != 2:\n return False\n \n month, day, year = date.split('-')\n \n try:\n month = int(month)\n day = int(day)\n year = int(year)\n except ValueError:\n return False\n \n if month < 1 or month > 12:\n return False\n \n if month in [1, 3, 5, 7, 8, 10, 12]:\n if day < 1 or day > 31:\n return False\n elif month in [4, 6, 9, 11]:\n if day < 1 or day > 30:\n return False\n elif month == 2:\n if day < 1 or day > 29:\n return False\n \n return True\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/125", "completion": "def split_words(txt):\n if any(char.isspace() for char in txt):\n return txt.split()\n elif ',' in txt:\n return txt.split(',')\n else:\n return sum(1 for char in txt if char.islower() and (ord(char) - ord('a')) % 2 == 0)\n", "result": "failed: ", "passed": false} +{"task_id": "HumanEval/126", "completion": "def is_sorted(lst):\n return lst == sorted(lst) and len(lst) == len(set(lst))\n", "result": "failed: This prints if this assert fails 7 (good for debugging!)", "passed": false} +{"task_id": "HumanEval/127", "completion": "def intersection(interval1, interval2):\n start1, end1 = interval1\n start2, end2 = interval2\n\n # Calculate the intersection\n start_intersection = max(start1, start2)\n end_intersection = min(end1, end2)\n\n # Check if there is an intersection\n if start_intersection >= end_intersection:\n return \"NO\"\n\n # Calculate length of the intersection\n length = end_intersection - start_intersection\n\n # Function to check if a number is prime\n def is_prime(n):\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n\n # Check if the length of the intersection is prime\n if is_prime(length):\n return \"YES\"\n else:\n return \"NO\"\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/128", "completion": "def prod_signs(arr):\n if not arr:\n return None\n \n product_of_signs = 1\n sum_of_magnitudes = 0\n \n for num in arr:\n if num > 0:\n sum_of_magnitudes += num\n elif num < 0:\n sum_of_magnitudes += -num\n product_of_signs *= -1\n else: # num == 0\n product_of_signs = 0\n \n return sum_of_magnitudes * product_of_signs\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/129", "completion": "def minPath(grid, k):\n from itertools import product\n \n n = len(grid)\n best_path = []\n\n def dfs(r, c, path):\n nonlocal best_path\n \n if len(path) == k:\n if not best_path or path < best_path:\n best_path = path[:]\n return\n \n directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]\n for dr, dc in directions:\n nr, nc = r + dr, c + dc\n if 0 <= nr < n and 0 <= nc < n:\n path.append(grid[nr][nc])\n dfs(nr, nc, path)\n path.pop()\n\n for i, j in product(range(n), repeat=2):\n dfs(i, j, [grid[i][j]])\n\n return best_path\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/130", "completion": "def tri(n):\n tribonacci = []\n \n for i in range(n + 1):\n if i == 0:\n tribonacci.append(1)\n elif i == 1:\n tribonacci.append(3)\n elif i % 2 == 0: # Even\n tribonacci.append(1 + i / 2)\n else: # Odd\n tribonacci.append(\n tribonacci[i - 1] + tribonacci[i - 2] + tribonacci[i + 1] if (i + 1 <= n) else tribonacci[i - 1] + tribonacci[i - 2]\n )\n \n return tribonacci\n", "result": "failed: ", "passed": false} +{"task_id": "HumanEval/131", "completion": "def digits(n):\n product = 1\n has_odd = False\n while n > 0:\n digit = n % 10\n if digit % 2 != 0: # Check if the digit is odd\n product *= digit\n has_odd = True\n n //= 10 # Remove the last digit\n return product if has_odd else 0\n ", "result": "passed", "passed": true} +{"task_id": "HumanEval/132", "completion": "def is_nested(string):\n stack = []\n nested = False\n\n for char in string:\n if char == '[':\n stack.append(char)\n elif char == ']':\n if stack:\n top = stack.pop()\n if stack: # Check if there are still brackets in the stack\n nested = True # We found a nested bracket\n else:\n return False # More closing brackets than opening\n\n # If there are still items in stack, that means we have unmatched opening brackets\n return nested\n\n# Example tests\nprint(is_nested('[[]]')) # \u279e True\nprint(is_nested('[]]]]]]][[[[[]')) # \u279e False\nprint(is_nested('[][]')) # \u279e False\nprint(is_nested('[]')) # \u279e False\nprint(is_nested('[[][]]')) # \u279e True\nprint(is_nested('[[]][[')) # \u279e True\n", "result": "failed: ", "passed": false} +{"task_id": "HumanEval/133", "completion": "import math\n\ndef sum_squares(lst):\n return sum(math.ceil(x) ** 2 for x in lst)\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/134", "completion": "def check_if_last_char_is_a_letter(txt):\n txt = txt.rstrip() # Remove trailing spaces\n if len(txt) == 0: # Check if the string is empty\n return False\n last_char = txt[-1] # Get the last character\n\n # Check if last_char is a letter and is not part of a word\n return last_char.isalpha() and (len(txt) == 1 or txt[-2] == ' ')\n", "result": "failed: ", "passed": false} +{"task_id": "HumanEval/135", "completion": "for i in range(1, len(arr)):\n if arr[i] < arr[i - 1]:\n return i\n return -1\n", "result": "failed: unindent does not match any outer indentation level (, line 15)", "passed": false} +{"task_id": "HumanEval/136", "completion": "largest_smallest_integers(lst):\n largest_negative = None\n smallest_positive = None\n \n for number in lst:\n if number < 0:\n if largest_negative is None or number > largest_negative:\n largest_negative = number\n elif number > 0:\n if smallest_positive is None or number < smallest_positive:\n smallest_positive = number\n\n return (largest_negative, smallest_positive)\n", "result": "failed: invalid syntax (, line 14)", "passed": false} +{"task_id": "HumanEval/137", "completion": "def compare_one(a, b):\n def to_float(value):\n if isinstance(value, str):\n value = value.replace(',', '.') \n return float(value)\n\n try:\n float_a = to_float(a)\n float_b = to_float(b)\n except ValueError:\n return None\n\n if float_a > float_b:\n return a\n elif float_a < float_b:\n return b\n else:\n return None\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/138", "completion": "def is_equal_to_sum_even(n):\n return n >= 8 and n % 2 == 0\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/139", "completion": "def special_factorial(n):\n def factorial(x):\n if x == 0 or x == 1:\n return 1\n else:\n result = 1\n for i in range(2, x + 1):\n result *= i\n return result\n\n result = 1\n for i in range(1, n + 1):\n result *= factorial(i)\n \n return result\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/140", "completion": "def fix_spaces(text):\n import re\n text = text.lstrip(' ')\n text = re.sub(r' {2,}', '-', text)\n text = text.replace(' ', '_')\n if text.startswith('_'):\n text = '_' + text.strip('_')\n return text\n", "result": "failed: This prints if this assert fails 3 (good for debugging!)", "passed": false} +{"task_id": "HumanEval/141", "completion": "def file_name_check(file_name):\n # Check for one dot\n if file_name.count('.') != 1:\n return 'No'\n \n # Split the name into the part before and after the dot\n name_part, ext_part = file_name.split('.')\n \n # Check if the name part is empty and starts with a letter\n if not name_part or not name_part[0].isalpha():\n return 'No'\n \n # Check for valid file extensions\n valid_extensions = ['txt', 'exe', 'dll']\n if ext_part not in valid_extensions:\n return 'No'\n \n # Count the digits in the file name\n digit_count = sum(c.isdigit() for c in file_name)\n if digit_count > 3:\n return 'No'\n \n return 'Yes'\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/142", "completion": "def sum_squares(lst):\n total_sum = 0\n for index, value in enumerate(lst):\n if index % 3 == 0:\n total_sum += value ** 2\n elif index % 4 == 0:\n total_sum += value ** 3\n else:\n total_sum += value\n return total_sum\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/143", "completion": "def words_in_sentence(sentence):\n def is_prime(n):\n if n <= 1:\n return False\n for i in range(2, int(n**0.5) + 1):\n if n % i == 0:\n return False\n return True\n\n words = sentence.split()\n prime_length_words = [word for word in words if is_prime(len(word))]\n return ' '.join(prime_length_words)\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/144", "completion": "def simplify(x, n):\n num1, denom1 = map(int, x.split('/'))\n num2, denom2 = map(int, n.split('/'))\n \n result_numerator = num1 * num2\n result_denominator = denom1 * denom2\n \n return result_numerator % result_denominator == 0\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/145", "completion": "def order_by_points(nums):\n def sum_of_digits(n):\n return sum(int(digit) for digit in str(abs(n)))\n\n return sorted(nums, key=lambda x: (sum_of_digits(x), nums.index(x)))\n", "result": "failed: ", "passed": false} +{"task_id": "HumanEval/146", "completion": "def specialFilter(nums):\n count = 0\n for num in nums:\n if num > 10:\n num_str = str(num)\n first_digit = int(num_str[0])\n last_digit = int(num_str[-1])\n if first_digit % 2 != 0 and last_digit % 2 != 0:\n count += 1\n return count\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/147", "completion": "a = [i * i - i + 1 for i in range(1, n + 1)]\ncount = 0\n\n# Iterate through all possible triples\nfor i in range(n):\n for j in range(i + 1, n):\n for k in range(j + 1, n):\n if (a[i] + a[j] + a[k]) % 3 == 0:\n count += 1\n \nreturn count\n", "result": "failed: 'return' outside function (, line 26)", "passed": false} +{"task_id": "HumanEval/148", "completion": "def bf(planet1, planet2):\n planets = [\"Mercury\", \"Venus\", \"Earth\", \"Mars\", \"Jupiter\", \"Saturn\", \"Uranus\", \"Neptune\"]\n if planet1 not in planets or planet2 not in planets:\n return ()\n \n index1 = planets.index(planet1)\n index2 = planets.index(planet2)\n \n if index1 > index2:\n index1, index2 = index2, index1\n \n return tuple(planets[index1 + 1:index2])\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/149", "completion": "def sorted_list_sum(lst):\n # Remove strings with odd lengths\n filtered = [s for s in lst if len(s) % 2 == 0]\n # Sort by length and then alphabetically\n sorted_list = sorted(filtered, key=lambda x: (len(x), x))\n return sorted_list\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/150", "completion": "def x_or_y(n, x, y):\n def is_prime(num):\n if num <= 1:\n return False\n for i in range(2, int(num**0.5) + 1):\n if num % i == 0:\n return False\n return True\n \n return x if is_prime(n) else y\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/151", "completion": "def double_the_difference(lst):\n odd_squares_sum = sum(x ** 2 for x in lst if x >= 0 and x % 2 == 1)\n return odd_squares_sum\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/152", "completion": "def compare(game, guess):\n return [abs(g - s) for g, s in zip(guess, game)]\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/153", "completion": "def Strongest_Extension(class_name, extensions):\n strongest_extension = \"\"\n max_strength = float('-inf') # Initialize to negative infinity to find the max\n\n for extension in extensions:\n CAP = sum(1 for char in extension if char.isupper())\n SM = sum(1 for char in extension if char.islower())\n strength = CAP - SM\n \n if strength > max_strength: # Update if this extension is stronger\n max_strength = strength\n strongest_extension = extension\n\n return f\"{class_name}.{strongest_extension}\"\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/154", "completion": "def cycpattern_check(a, b):\n if len(b) == 0:\n return True\n return any(b[i:i+len(b)] in a for i in range(len(b)))\n", "result": "failed: test #0", "passed": false} +{"task_id": "HumanEval/155", "completion": "even_count = 0\n odd_count = 0\n\n for digit in str(abs(num)):\n if int(digit) % 2 == 0:\n even_count += 1\n else:\n odd_count += 1\n\n return (even_count, odd_count)\n", "result": "failed: unexpected indent (, line 10)", "passed": false} +{"task_id": "HumanEval/156", "completion": "def int_to_mini_roman(number):\n roman_numerals = [\n (1000, 'm'), (900, 'cm'), (500, 'd'), (400, 'cd'),\n (100, 'c'), (90, 'xc'), (50, 'l'), (40, 'xl'),\n (10, 'x'), (9, 'ix'), (5, 'v'), (4, 'iv'), (1, 'i')\n ]\n \n result = \"\"\n \n for value, numeral in roman_numerals:\n while number >= value:\n result += numeral\n number -= value\n \n return result\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/157", "completion": "sides = sorted([a, b, c])\nreturn sides[0]**2 + sides[1]**2 == sides[2]**2\n", "result": "failed: 'return' outside function (, line 13)", "passed": false} +{"task_id": "HumanEval/158", "completion": "def find_max(words):\n max_word = \"\"\n max_unique_count = 0\n \n for word in words:\n unique_chars = len(set(word))\n \n if (unique_chars > max_unique_count or \n (unique_chars == max_unique_count and word < max_word)):\n max_word = word\n max_unique_count = unique_chars\n \n return max_word\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/159", "completion": "def eat(number, need, remaining):\n total_eaten = number\n if need <= remaining:\n total_eaten += need\n remaining -= need\n else:\n total_eaten += remaining\n remaining = 0\n return [total_eaten, remaining]\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/160", "completion": "def do_algebra(operator, operand):\n result = operand[0]\n for i in range(len(operator)):\n if operator[i] == '+':\n result += operand[i + 1]\n elif operator[i] == '-':\n result -= operand[i + 1]\n elif operator[i] == '*':\n result *= operand[i + 1]\n elif operator[i] == '//':\n result //= operand[i + 1]\n elif operator[i] == '**':\n result **= operand[i + 1]\n return result\n", "result": "failed: ", "passed": false} +{"task_id": "HumanEval/161", "completion": "def solve(s):\n # Check if there are any letters in the input string\n has_letter = any(c.isalpha() for c in s)\n\n if not has_letter:\n # Reverse the string if no letters are present\n return s[::-1]\n else:\n # Create a list to hold the new characters\n result = []\n # Iterate through each character in the string\n for c in s:\n if c.isalpha():\n # Reverse case for letters\n if c.islower():\n result.append(c.upper())\n else:\n result.append(c.lower())\n else:\n # Keep non-letter characters as they are\n result.append(c)\n return ''.join(result)\n ", "result": "passed", "passed": true} +{"task_id": "HumanEval/162", "completion": "import hashlib\n\ndef string_to_md5(text):\n if text == \"\":\n return None\n hash_object = hashlib.md5(text.encode())\n return hash_object.hexdigest()\n", "result": "passed", "passed": true} +{"task_id": "HumanEval/163", "completion": "def generate_integers(a, b):\n lower = min(a, b)\n upper = max(a, b)\n return [n for n in range(lower, upper + 1) if n % 2 == 0]\n", "result": "failed: Test 1", "passed": false} From 4c5b135d95773c3b7b71166b3f22698129ff6897 Mon Sep 17 00:00:00 2001 From: dongyuanjushi Date: Sun, 3 Nov 2024 10:30:20 -0500 Subject: [PATCH 26/41] update --- aios/context/simple_context.py | 19 +++++--- aios/hooks/{request.py => syscall.py} | 48 +++++++++++-------- aios/sdk/autogen/client_adapter.py | 2 +- aios/sdk/interpreter/adapter.py | 2 +- aios/sdk/metagpt/adapter.py | 2 +- experiment/agent/experiment_agent.py | 29 +++++++++++ pyopenagi/agents/base_agent.py | 2 +- .../agents/example/academic_agent/agent.py | 2 +- pyopenagi/agents/react_agent.py | 2 +- 9 files changed, 75 insertions(+), 33 deletions(-) rename aios/hooks/{request.py => syscall.py} (76%) create mode 100644 experiment/agent/experiment_agent.py diff --git a/aios/context/simple_context.py b/aios/context/simple_context.py index d6e95d054..112b7ca14 100644 --- a/aios/context/simple_context.py +++ b/aios/context/simple_context.py @@ -8,28 +8,35 @@ import torch # import shutil +from threading import Lock class SimpleContextManager(BaseContextManager): def __init__(self): BaseContextManager.__init__(self) + self.context_dict = {} def start(self): pass def gen_snapshot(self, pid, context): - file_path = os.path.join(self.context_dir, f"process-{pid}.pt") - torch.save(context, file_path) + # file_path = os.path.join(self.context_dir, f"process-{pid}.pt") + # torch.save(context, file_path) + self.context_dic[str(pid)] = context def gen_recover(self, pid): - file_path = os.path.join(self.context_dir, f"process-{pid}.pt") - return torch.load(file_path) + # file_path = os.path.join(self.context_dir, f"process-{pid}.pt") + # return torch.load(file_path) + return self.context_dict[str(pid)] def check_restoration(self, pid): - return os.path.exists(os.path.join(self.context_dir, f"process-{pid}.pt")) + # return os.path.exists(os.path.join(self.context_dir, f"process-{pid}.pt")) + return str(pid) in self.context_dict.keys() def clear_restoration(self, pid): # print(f"Process {pid} has been deleted.") - os.remove(os.path.join(self.context_dir, f"process-{pid}.pt")) + # os.remove(os.path.join(self.context_dir, f"process-{pid}.pt")) + self.context_dict.pop(pid) + return def stop(self): pass diff --git a/aios/hooks/request.py b/aios/hooks/syscall.py similarity index 76% rename from aios/hooks/request.py rename to aios/hooks/syscall.py index afbd4ccf1..5b9065757 100755 --- a/aios/hooks/request.py +++ b/aios/hooks/syscall.py @@ -6,7 +6,7 @@ from aios.hooks.stores._global import global_llm_req_queue_add_message -class AgentRequest(Thread): +class Syscall(Thread): def __init__(self, agent_name, query): """Agent Process @@ -92,16 +92,22 @@ def run(self): self.set_pid(self.native_id) self.event.wait() -class LLMRequest(AgentRequest): + +class LLMSyscall(Syscall): + pass + + +class MemSyscall(Syscall): + pass + + +class StorageSyscall(Syscall): pass def send_request(agent_name, query): - agent_request = AgentRequest( - agent_name=agent_name, - query=query - ) - agent_request.set_status("active") + syscall = LLMSyscall(agent_name=agent_name, query=query) + syscall.set_status("active") completed_response, start_times, end_times, waiting_times, turnaround_times = ( "", @@ -111,24 +117,24 @@ def send_request(agent_name, query): [], ) - while agent_request.get_status() != "done": + while syscall.get_status() != "done": current_time = time.time() - agent_request.set_created_time(current_time) - agent_request.set_response(None) + syscall.set_created_time(current_time) + syscall.set_response(None) - global_llm_req_queue_add_message(agent_request) + global_llm_req_queue_add_message(syscall) - agent_request.start() - agent_request.join() + syscall.start() + syscall.join() - completed_response = agent_request.get_response() - - if agent_request.get_status() != "done": + completed_response = syscall.get_response() + + if syscall.get_status() != "done": pass - start_time = agent_request.get_start_time() - end_time = agent_request.get_end_time() - waiting_time = start_time - agent_request.get_created_time() - turnaround_time = end_time - agent_request.get_created_time() + start_time = syscall.get_start_time() + end_time = syscall.get_end_time() + waiting_time = start_time - syscall.get_created_time() + turnaround_time = end_time - syscall.get_created_time() start_times.append(start_time) end_times.append(end_time) @@ -141,4 +147,4 @@ def send_request(agent_name, query): end_times, waiting_times, turnaround_times, - ) \ No newline at end of file + ) diff --git a/aios/sdk/autogen/client_adapter.py b/aios/sdk/autogen/client_adapter.py index 4b7e0e156..89adabe7f 100644 --- a/aios/sdk/autogen/client_adapter.py +++ b/aios/sdk/autogen/client_adapter.py @@ -14,7 +14,7 @@ from autogen.runtime_logging import logging_enabled, log_new_wrapper, log_chat_completion from openai import APITimeoutError, APIError -from aios.hooks.request import send_request +from aios.hooks.syscall import send_request from pyopenagi.utils.chat_template import Query try: diff --git a/aios/sdk/interpreter/adapter.py b/aios/sdk/interpreter/adapter.py index 0eefecd56..9c7ec51c1 100644 --- a/aios/sdk/interpreter/adapter.py +++ b/aios/sdk/interpreter/adapter.py @@ -3,7 +3,7 @@ import json import sys -from aios.hooks.request import send_request +from aios.hooks.syscall import send_request from aios.sdk.adapter import add_framework_adapter from aios.utils.logger import SDKLogger from pyopenagi.utils.chat_template import Query diff --git a/aios/sdk/metagpt/adapter.py b/aios/sdk/metagpt/adapter.py index 42b38401f..a1f64de71 100644 --- a/aios/sdk/metagpt/adapter.py +++ b/aios/sdk/metagpt/adapter.py @@ -5,7 +5,7 @@ from pyopenagi.utils.chat_template import Query from .config_adapter import prepare_metagpt_config from ..adapter import add_framework_adapter -from ...hooks.request import send_request +from ...hooks.syscall import send_request try: from metagpt.provider.base_llm import BaseLLM diff --git a/experiment/agent/experiment_agent.py b/experiment/agent/experiment_agent.py new file mode 100644 index 000000000..32c6a0470 --- /dev/null +++ b/experiment/agent/experiment_agent.py @@ -0,0 +1,29 @@ +from abc import ABC, abstractmethod + +from aios.hooks.syscall import send_request +from pyopenagi.utils.chat_template import Query + + +class ExpirementAgent(ABC): + + @abstractmethod + def run(self, input_str: str): + pass + + +class SimpleLLMAgent(ExpirementAgent): + + def __init__(self, on_aios: bool = True): + self.agent_name = "gpt" + self.on_aios = on_aios + + def run(self, input_str: str): + message = {"content": input_str, "role": "user"} + query = Query(messages=[message], tools=None) + + response, _, _, _, _ = send_request( + agent_name=self.agent_name, + query=query + ) + result = response.response_message + return result diff --git a/pyopenagi/agents/base_agent.py b/pyopenagi/agents/base_agent.py index 8e70f27ff..d173ba208 100755 --- a/pyopenagi/agents/base_agent.py +++ b/pyopenagi/agents/base_agent.py @@ -14,7 +14,7 @@ import importlib -from aios.hooks.request import send_request +from aios.hooks.syscall import send_request class BaseAgent: def __init__(self, agent_name, task_input, log_mode: str): diff --git a/pyopenagi/agents/example/academic_agent/agent.py b/pyopenagi/agents/example/academic_agent/agent.py index cafc614b6..59b29cf6e 100644 --- a/pyopenagi/agents/example/academic_agent/agent.py +++ b/pyopenagi/agents/example/academic_agent/agent.py @@ -3,7 +3,7 @@ import os import time -from aios.hooks.request import send_request +from aios.hooks.syscall import send_request from pyopenagi.utils.chat_template import Query diff --git a/pyopenagi/agents/react_agent.py b/pyopenagi/agents/react_agent.py index 78e1a931f..d662bcc05 100644 --- a/pyopenagi/agents/react_agent.py +++ b/pyopenagi/agents/react_agent.py @@ -7,7 +7,7 @@ import json -from aios.hooks.request import send_request +from aios.hooks.syscall import send_request class ReactAgent(BaseAgent): def __init__(self, From 0c76d8ece8feef4a1bbdf53667361087965c01c5 Mon Sep 17 00:00:00 2001 From: 2020-qqtcg Date: Tue, 5 Nov 2024 14:21:02 +0800 Subject: [PATCH 27/41] feat: standard agent --- experiment/benchmark/__init__.py | 0 experiment/benchmark/gaia.py | 0 experiment/benchmark/gaia/__init__.py | 0 experiment/benchmark/gaia/init_data.py | 25 ++++++++++++++++ experiment/benchmark/gaia/run_infer.py | 29 +++++++++++++++++++ pyopenagi/agents/experiment/standard/agent.py | 2 +- 6 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 experiment/benchmark/__init__.py create mode 100644 experiment/benchmark/gaia.py create mode 100644 experiment/benchmark/gaia/__init__.py create mode 100644 experiment/benchmark/gaia/init_data.py create mode 100644 experiment/benchmark/gaia/run_infer.py diff --git a/experiment/benchmark/__init__.py b/experiment/benchmark/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/experiment/benchmark/gaia.py b/experiment/benchmark/gaia.py new file mode 100644 index 000000000..e69de29bb diff --git a/experiment/benchmark/gaia/__init__.py b/experiment/benchmark/gaia/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/experiment/benchmark/gaia/init_data.py b/experiment/benchmark/gaia/init_data.py new file mode 100644 index 000000000..2141f4654 --- /dev/null +++ b/experiment/benchmark/gaia/init_data.py @@ -0,0 +1,25 @@ +import os + +from huggingface_hub import snapshot_download + +DOWNLOAD_PATH = os.path.dirname(os.path.realpath(__file__)) +REPO_PATH = os.path.join(DOWNLOAD_PATH, "gaia") + + +def download_gaia(): + """Download the GAIA benchmark from Hugging Face.""" + + if not os.path.isdir(DOWNLOAD_PATH): + os.mkdir(DOWNLOAD_PATH) + + """Download the GAIA dataset from Hugging Face Hub""" + snapshot_download( + repo_id="gaia-benchmark/GAIA", + repo_type="dataset", + local_dir_use_symlinks=True, + local_dir=REPO_PATH, + ) + + +if __name__ == "__main__": + download_gaia() diff --git a/experiment/benchmark/gaia/run_infer.py b/experiment/benchmark/gaia/run_infer.py new file mode 100644 index 000000000..85543c3b7 --- /dev/null +++ b/experiment/benchmark/gaia/run_infer.py @@ -0,0 +1,29 @@ +from aios.hooks.llm import aios_starter +from aios.utils.utils import parse_global_args +from pyopenagi.agents.experiment.standard.agent import StandardAgent + + +def process_one_func(input_str: str): + agent = StandardAgent("Standard Agent", input_str) + result = agent.run() + print(result) + + +def run_infer(aios_args: dict): + + with aios_starter(*aios_args): + process_one_func("") + + +if __name__ == '__main__': + parser = parse_global_args() + + args = parser.parse_args() + aios_args = { + "llm_name": args.llm_name, + "max_gpu_memory": args.max_gpu_memory, + "eval_device": args.eval_device, + "max_new_tokens": args.max_new_tokens, + "log_mode": args.log_mode, + "use_backend": args.use_backend, + } diff --git a/pyopenagi/agents/experiment/standard/agent.py b/pyopenagi/agents/experiment/standard/agent.py index 624a7f333..3b6c74f0b 100644 --- a/pyopenagi/agents/experiment/standard/agent.py +++ b/pyopenagi/agents/experiment/standard/agent.py @@ -12,7 +12,7 @@ class StandardAgent: - def __init__(self, agent_name: str, task_input: str, log_mode: str): + def __init__(self, agent_name: str, task_input: str, log_mode: str = "console"): # Init module self.planning: Planning | None = None self.actions = {} From d0d2c28ffdc406854e5f7bdf564f0d3e551fcd0a Mon Sep 17 00:00:00 2001 From: 2020-qqtcg Date: Tue, 5 Nov 2024 15:28:54 +0800 Subject: [PATCH 28/41] feat: experiment --- experiment/benchmark/gaia/run_infer.py | 65 +++++++++++++++++-- .../experiment/standard/action/action_tool.py | 7 +- .../standard/prompt/framework_prompt.py | 1 + 3 files changed, 65 insertions(+), 8 deletions(-) diff --git a/experiment/benchmark/gaia/run_infer.py b/experiment/benchmark/gaia/run_infer.py index 85543c3b7..3d74e1a92 100644 --- a/experiment/benchmark/gaia/run_infer.py +++ b/experiment/benchmark/gaia/run_infer.py @@ -1,22 +1,69 @@ +import json +import os +from concurrent.futures import ThreadPoolExecutor, as_completed + +from tqdm import tqdm + from aios.hooks.llm import aios_starter from aios.utils.utils import parse_global_args from pyopenagi.agents.experiment.standard.agent import StandardAgent +DATA_PATH = os.path.join( + os.path.dirname(os.path.realpath(__file__)), + "gaia", + "2023", + "validation" +) + -def process_one_func(input_str: str): - agent = StandardAgent("Standard Agent", input_str) +def process_one_func(data): + agent = StandardAgent("Standard Agent", data["Question"]) result = agent.run() print(result) + return { + "task_id": 1, + "result": data["Question"] + } + + +def prepare_dataset(): + input_file = os.path.join(DATA_PATH, "metadata.jsonl") + with open(input_file, "r") as file: + dataset = [json.loads(line) for line in file] + return dataset -def run_infer(aios_args: dict): - with aios_starter(*aios_args): - process_one_func("") +def run_infer(outputfile: str, workers: int, aios_args: dict): + dataset = prepare_dataset() + + with ThreadPoolExecutor(max_workers=workers) as executor: + with aios_starter(**aios_args): + futures = [] + for data in dataset: + # 提交任务 + futures.append( + executor.submit(process_one_func, data) + ) + break + + results = [] + + # Obtain infer result + for future in tqdm(as_completed(futures)): + results.append(future.result()) + + # Write result into .jsonl file + with open(outputfile, "w") as file: + for line in results: + json_line = json.dumps(line) + file.write(json_line + "\n") if __name__ == '__main__': parser = parse_global_args() + parser.add_argument("--output_file", type=str, default="./experiment/benchmark/gaia/predictions.jsonl") + parser.add_argument("--workers", type=int, default=1) args = parser.parse_args() aios_args = { @@ -24,6 +71,12 @@ def run_infer(aios_args: dict): "max_gpu_memory": args.max_gpu_memory, "eval_device": args.eval_device, "max_new_tokens": args.max_new_tokens, - "log_mode": args.log_mode, + "log_mode": "console", "use_backend": args.use_backend, } + + run_infer( + args.output_file, + args.workers, + aios_args + ) diff --git a/pyopenagi/agents/experiment/standard/action/action_tool.py b/pyopenagi/agents/experiment/standard/action/action_tool.py index af432bb9d..fdc4a69ff 100644 --- a/pyopenagi/agents/experiment/standard/action/action_tool.py +++ b/pyopenagi/agents/experiment/standard/action/action_tool.py @@ -1,6 +1,6 @@ import importlib from typing import List, Any, Optional -from pydantic.v1 import BaseModel, root_validator +from pydantic.v1 import BaseModel from pyopenagi.agents.experiment.standard.action.action import Action from pyopenagi.agents.experiment.standard.utils.config import Config from pyopenagi.agents.experiment.standard.utils.str_utils import snake_to_camel @@ -13,6 +13,10 @@ class ActionTool(Action, BaseModel): tools_format: Optional[List] type: str = "TOOL" + def __int__(self, *data): + super().__init__(self, *data) + self.init_tools() + def __call__(self, tool_call: dict) -> Any: if tool_call is None: return @@ -28,7 +32,6 @@ def __call__(self, tool_call: dict) -> Any: return function_response - @root_validator(pre=True) def init_tools(self): self._init_tools_from_config() diff --git a/pyopenagi/agents/experiment/standard/prompt/framework_prompt.py b/pyopenagi/agents/experiment/standard/prompt/framework_prompt.py index 8b8290606..2bebebf41 100644 --- a/pyopenagi/agents/experiment/standard/prompt/framework_prompt.py +++ b/pyopenagi/agents/experiment/standard/prompt/framework_prompt.py @@ -27,4 +27,5 @@ {communication} +If you think the task is done, reply TERMINATE. """ From 2160ef385ed18b103c593ee0550191ba466f3e44 Mon Sep 17 00:00:00 2001 From: dongyuanjushi Date: Tue, 5 Nov 2024 11:19:56 -0500 Subject: [PATCH 29/41] refactor kernel function --- aios/hooks/llm.py | 178 +++++++++++ aios/hooks/modules/llm.py | 2 +- aios/hooks/modules/memory.py | 6 +- aios/hooks/modules/storage.py | 18 +- aios/hooks/modules/tool.py | 21 +- aios/hooks/parser.py | 31 ++ aios/hooks/starter.py | 21 +- aios/hooks/syscall.py | 186 +++++++++-- aios/hooks/types/memory.py | 7 +- aios/hooks/types/scheduler.py | 7 +- aios/hooks/types/storage.py | 6 +- aios/hooks/types/tool.py | 2 +- aios/hooks/utils.py | 5 + aios/hooks/validate.py | 20 ++ aios/llm_core/llm_classes/gemini_llm.py | 8 +- aios/llm_core/llm_classes/gpt_llm.py | 4 +- aios/memory/manager.py | 22 ++ aios/memory/memory_classes/shared_memory.py | 17 ++ aios/memory/memory_classes/single_memory.py | 66 ++++ aios/scheduler/fifo_scheduler.py | 4 +- aios/storage/storage.py | 84 +++++ aios/storage/storage_classes/db_storage.py | 82 +++++ aios/tool/manager.py | 38 +++ experiment/agent/experiment_agent.py | 8 +- .../agents/example/academic_agent/agent.py | 288 +++--------------- .../agents/experiment/standard/__init__.py | 0 .../experiment/standard/action/__init__.py | 0 .../experiment/standard/action/action.py | 12 + .../experiment/standard/action/action_code.py | 0 .../experiment/standard/action/action_tool.py | 60 ++++ pyopenagi/agents/experiment/standard/agent.py | 157 ++++++++++ .../standard/communication/__init__.py | 0 .../standard/communication/communication.py | 0 .../agents/experiment/standard/config.json | 18 ++ .../experiment/standard/memory/__init__.py | 0 .../experiment/standard/memory/memory.py | 2 + .../standard/memory/short_term_memory.py | 23 ++ .../experiment/standard/planning/__init__.py | 0 .../experiment/standard/planning/planning.py | 49 +++ .../experiment/standard/prompt/__init__.py | 0 .../standard/prompt/framework_prompt.py | 30 ++ .../experiment/standard/utils/__init__.py | 0 .../experiment/standard/utils/config.py | 25 ++ .../experiment/standard/utils/str_utils.py | 3 + pyopenagi/queues/base_queue.py | 17 ++ pyopenagi/queues/llm_request_queue.py | 4 + pyopenagi/utils/chat_template.py | 22 +- standard_main.py | 30 ++ 48 files changed, 1275 insertions(+), 308 deletions(-) create mode 100644 aios/hooks/llm.py create mode 100644 aios/hooks/parser.py create mode 100644 aios/hooks/utils.py create mode 100644 aios/hooks/validate.py create mode 100644 aios/memory/manager.py create mode 100644 aios/memory/memory_classes/shared_memory.py create mode 100644 aios/memory/memory_classes/single_memory.py create mode 100644 aios/storage/storage.py create mode 100644 aios/storage/storage_classes/db_storage.py create mode 100644 aios/tool/manager.py create mode 100644 pyopenagi/agents/experiment/standard/__init__.py create mode 100644 pyopenagi/agents/experiment/standard/action/__init__.py create mode 100644 pyopenagi/agents/experiment/standard/action/action.py create mode 100644 pyopenagi/agents/experiment/standard/action/action_code.py create mode 100644 pyopenagi/agents/experiment/standard/action/action_tool.py create mode 100644 pyopenagi/agents/experiment/standard/agent.py create mode 100644 pyopenagi/agents/experiment/standard/communication/__init__.py create mode 100644 pyopenagi/agents/experiment/standard/communication/communication.py create mode 100644 pyopenagi/agents/experiment/standard/config.json create mode 100644 pyopenagi/agents/experiment/standard/memory/__init__.py create mode 100644 pyopenagi/agents/experiment/standard/memory/memory.py create mode 100644 pyopenagi/agents/experiment/standard/memory/short_term_memory.py create mode 100644 pyopenagi/agents/experiment/standard/planning/__init__.py create mode 100644 pyopenagi/agents/experiment/standard/planning/planning.py create mode 100644 pyopenagi/agents/experiment/standard/prompt/__init__.py create mode 100644 pyopenagi/agents/experiment/standard/prompt/framework_prompt.py create mode 100644 pyopenagi/agents/experiment/standard/utils/__init__.py create mode 100644 pyopenagi/agents/experiment/standard/utils/config.py create mode 100644 pyopenagi/agents/experiment/standard/utils/str_utils.py create mode 100644 pyopenagi/queues/base_queue.py create mode 100644 pyopenagi/queues/llm_request_queue.py create mode 100644 standard_main.py diff --git a/aios/hooks/llm.py b/aios/hooks/llm.py new file mode 100644 index 000000000..90a0c2e01 --- /dev/null +++ b/aios/hooks/llm.py @@ -0,0 +1,178 @@ +from concurrent.futures import ThreadPoolExecutor, Future +from contextlib import contextmanager + +from typing import Any +from random import randint + +from aios.llm_core.llms import LLM + +from aios.scheduler.fifo_scheduler import FIFOScheduler + +from aios.hooks.types.llm import AgentSubmitDeclaration, FactoryParams, LLMParams, SchedulerParams, LLMRequestQueue, \ + QueueGetMessage, QueueAddMessage, QueueCheckEmpty +from aios.hooks.validate import validate + +from aios.hooks.stores import queue as QueueStore, processes as ProcessStore + +from aios.hooks.utils import generate_random_string + +from pyopenagi.agents.agent_factory import AgentFactory + +ids = [] + + +@validate(LLMParams) +def useKernel(params: LLMParams) -> LLM: + return LLM(**params.model_dump()) + + +def useLLMRequestQueue() -> tuple[LLMRequestQueue, QueueGetMessage, QueueAddMessage, QueueCheckEmpty]: + r_str = generate_random_string() + _ = LLMRequestQueue() + + QueueStore.LLM_REQUEST_QUEUE[r_str] = _ + + def getMessage(): + return QueueStore.getMessage(_) + + def addMessage(message: str): + return QueueStore.addMessage(_, message) + + def isEmpty(): + return QueueStore.isEmpty(_) + + return _, getMessage, addMessage, isEmpty + + +@validate(SchedulerParams) +def useFIFOScheduler(params: SchedulerParams): + if params.get_queue_message is None: + from aios.hooks.stores._global import global_llm_req_queue_get_message + + params.get_queue_message = global_llm_req_queue_get_message + + scheduler = FIFOScheduler(**params.model_dump()) + + def startScheduler(): + scheduler.start() + + def stopScheduler(): + scheduler.stop() + + return startScheduler, stopScheduler + + +@validate(FactoryParams) +def useFactory(params: FactoryParams): + # process_factory = AgentProcessFactory() + + agent_factory = AgentFactory( + # agent_process_factory=process_factory, + agent_log_mode=params.log_mode, + ) + + thread_pool = ThreadPoolExecutor(max_workers=params.max_workers) + + @validate(AgentSubmitDeclaration) + def submitAgent(declaration_params: AgentSubmitDeclaration) -> None: + _submitted_agent: Future = thread_pool.submit( + agent_factory.run_agent, + declaration_params.agent_name, + declaration_params.task_input + ) + # _submitted_agent = + + random_code = randint(100000, 999999) + + while random_code in ids: + random_code = randint(100000, 999999) + + ProcessStore.addProcess(_submitted_agent, random_code) + + return random_code + + # def awaitAgentExecution() -> dict[str, Any]: + # res = [] + + # for r in as_completed(ProcessStore.AGENT_PROCESSES): + # _ = r.result() + # res.append(_) + + # return res + + def awaitAgentExecution(process_id: str) -> dict[str, Any]: + future = ProcessStore.AGENT_PROCESSES.get(process_id) + + if future: + # with threading.Lock(): + # ids = [x for x in ids if x != process_id] + return future.result() + else: + raise ValueError(f"Process with ID '{process_id}' not found.") + + return submitAgent, awaitAgentExecution + + +@contextmanager +@validate(SchedulerParams) +def fifo_scheduler(params: SchedulerParams): + """ + A context manager that starts and stops a FIFO scheduler. + + Args: + params (SchedulerParams): The parameters for the scheduler. + """ + if params.get_queue_message is None: + from aios.hooks.stores._global import global_llm_req_queue_get_message + params.get_queue_message = global_llm_req_queue_get_message + + scheduler = FIFOScheduler(**params.model_dump()) + + scheduler.start() + yield + scheduler.stop() + + +@contextmanager +def aios_starter( + llm_name, + max_gpu_memory, + eval_device, + max_new_tokens, + log_mode, + use_backend +): + """ + Starts a LLM kernel and a scheduler for running agents, + returning a submitAgent and awaitAgentExecution function. + + Args: + llm_name (str): The name of the LLM kernel to use. + max_gpu_memory (str): The maximum amount of GPU memory to use. + eval_device (str): The device to evaluate the LLM on. + max_new_tokens (int): The maximum number of new tokens to generate. + log_mode (str): The log mode. + use_backend (str): The backend to use for running the LLM kernel. + + Yields: + submitAgent (Callable[[str, str], str]): A function that submits an agent for execution. + awaitAgentExecution (Callable[[str], dict[str, Any]]): A function that waits for an agent + to complete and returns its result. + """ + llm = useKernel( + llm_name=llm_name, + max_gpu_memory=max_gpu_memory, + eval_device=eval_device, + max_new_tokens=max_new_tokens, + log_mode=log_mode, + use_backend=use_backend + ) + + # run agents concurrently for maximum efficiency using a scheduler + submit_agent, await_agent_execution = useFactory( + log_mode=log_mode, + max_workers=64 + ) + + with fifo_scheduler(llm=llm, log_mode=log_mode, get_queue_message=None): + yield submit_agent, await_agent_execution diff --git a/aios/hooks/modules/llm.py b/aios/hooks/modules/llm.py index 23c6da0cb..e76063674 100644 --- a/aios/hooks/modules/llm.py +++ b/aios/hooks/modules/llm.py @@ -19,7 +19,7 @@ @validate(LLMParams) -def useKernel(params: LLMParams) -> LLM: +def useCore(params: LLMParams) -> LLM: """ Initialize and return a Language Learning Model (LLM) instance. diff --git a/aios/hooks/modules/memory.py b/aios/hooks/modules/memory.py index 8fe6d4175..04997cc26 100644 --- a/aios/hooks/modules/memory.py +++ b/aios/hooks/modules/memory.py @@ -9,6 +9,10 @@ from aios.hooks.utils.validate import validate from aios.hooks.stores import queue as QueueStore +from aios.hooks.types.memory import MemoryManagerParams + +from aios.memory.manager import MemoryManager + def useMemoryRequestQueue() -> ( Tuple[MemoryRequestQueue, MemoryRequestQueueGetMessage, MemoryRequestQueueAddMessage, MemoryRequestQueueCheckEmpty] ): @@ -41,7 +45,7 @@ def isEmpty(): return _, getMessage, addMessage, isEmpty -# @validate(MemoryManagerParams) +@validate(MemoryManagerParams) def useMemoryManager(params): """ Initialize and return a memory instance. diff --git a/aios/hooks/modules/storage.py b/aios/hooks/modules/storage.py index 921c1751c..7f40d4451 100644 --- a/aios/hooks/modules/storage.py +++ b/aios/hooks/modules/storage.py @@ -8,6 +8,9 @@ ) from aios.hooks.utils.validate import validate from aios.hooks.stores import queue as QueueStore +from aios.storage.storage import StorageManager + +from aios.hooks.types.storage import StorageManagerParams def useStorageRequestQueue() -> ( Tuple[StorageRequestQueue, StorageRequestQueueGetMessage, StorageRequestQueueAddMessage, StorageRequestQueueCheckEmpty] @@ -41,15 +44,6 @@ def isEmpty(): return _, getMessage, addMessage, isEmpty -# @validate(MemoryManagerParams) -# def useMemoryManager(params: MemoryManagerParams) -> MemoryManager: -# """ -# Initialize and return a memory instance. - -# Args: -# params (MemoryParams): Parameters required for Memory Manager Initialization. - -# Returns: -# Memory Manager: An instance of the initialized Memory Manager. -# """ -# return MemoryManager(**params.model_dump()) \ No newline at end of file +@validate(StorageManagerParams) +def useStorageManager(params: StorageManagerParams) -> StorageManager: + return StorageManager(**params.model_dump()) \ No newline at end of file diff --git a/aios/hooks/modules/tool.py b/aios/hooks/modules/tool.py index 8435b0397..44aa851e8 100644 --- a/aios/hooks/modules/tool.py +++ b/aios/hooks/modules/tool.py @@ -2,7 +2,7 @@ from typing import Tuple -from aios.tool.base import ToolManager +from aios.tool.manager import ToolManager from aios.hooks.types.tool import ( ToolRequestQueue, ToolRequestQueueAddMessage, @@ -13,7 +13,7 @@ from aios.hooks.stores import queue as QueueStore, processes as ProcessStore # @validate(ToolManagerParams) -def useToolManager(params) -> ToolManager: +def useToolManager() -> ToolManager: """ Initialize and return a tool manager instance. @@ -23,7 +23,7 @@ def useToolManager(params) -> ToolManager: Returns: Tool Manager: An instance of the initialized Tool Manager. """ - return ToolManager(**params.model_dump()) + return ToolManager() def useToolRequestQueue() -> ( Tuple[ToolRequestQueue, ToolRequestQueueGetMessage, ToolRequestQueueAddMessage, ToolRequestQueueCheckEmpty] @@ -55,17 +55,4 @@ def addMessage(message: str): def isEmpty(): return QueueStore.isEmpty(_) - return _, getMessage, addMessage, isEmpty - -# @validate(MemoryManagerParams) -# def useMemoryManager(params: MemoryManagerParams) -> MemoryManager: -# """ -# Initialize and return a memory instance. - -# Args: -# params (MemoryParams): Parameters required for Memory Manager Initialization. - -# Returns: -# Memory Manager: An instance of the initialized Memory Manager. -# """ -# return MemoryManager(**params.model_dump()) \ No newline at end of file + return _, getMessage, addMessage, isEmpty \ No newline at end of file diff --git a/aios/hooks/parser.py b/aios/hooks/parser.py new file mode 100644 index 000000000..da0b1fb88 --- /dev/null +++ b/aios/hooks/parser.py @@ -0,0 +1,31 @@ +from aios.core.types import _obj, array, string, integer, _float +from aios.core.schema import CoreSchema +from aios.core import complete + +def useCompletion(): + """ + Wrapper for internal complete function + """ + + def _( + name: str, + message: str, + system_message: str | None = None, + temperature: float = 0.3, + max_tokens: float | None = None, + json: bool = False, + schema: CoreSchema | None = None + ): + return complete( + name, + message, + system_message, + temperature, + max_tokens, + json, + schema + ) + + return _ + + \ No newline at end of file diff --git a/aios/hooks/starter.py b/aios/hooks/starter.py index fb7ca73fe..25afead9d 100644 --- a/aios/hooks/starter.py +++ b/aios/hooks/starter.py @@ -1,6 +1,9 @@ from contextlib import contextmanager from typing import Tuple, Callable, Dict, Any -from .modules.llm import useKernel +from .modules.llm import useCore +from .modules.memory import useMemoryManager +from .modules.storage import useStorageManager +from .modules.tool import useToolManager from .modules.agent import useFactory from .modules.scheduler import fifo_scheduler @@ -32,7 +35,7 @@ def aios_starter( Yields: Tuple: A tuple containing the submitAgent and awaitAgentExecution functions. """ - llm = useKernel( + llm = useCore( llm_name=llm_name, max_gpu_memory=max_gpu_memory, eval_device=eval_device, @@ -40,6 +43,17 @@ def aios_starter( log_mode=llm_kernel_log_mode, use_backend=use_backend, ) + storage_manager = useStorageManager( + root_dir = "root", + use_vector_db = False + ) + + memory_manager = useMemoryManager( + memory_limit = 100*1024*1024, + eviction_k = 10, + storage_manager = storage_manager + ) + tool_manager = useToolManager() submit_agent, await_agent_execution = useFactory( log_mode=agent_log_mode, max_workers=64 @@ -47,6 +61,9 @@ def aios_starter( with fifo_scheduler( llm=llm, + memory_manager=memory_manager, + storage_manager=storage_manager, + tool_manager=tool_manager, log_mode=scheduler_log_mode, get_llm_request=None, get_memory_request=None, diff --git a/aios/hooks/syscall.py b/aios/hooks/syscall.py index 5b9065757..feed15d7f 100755 --- a/aios/hooks/syscall.py +++ b/aios/hooks/syscall.py @@ -3,7 +3,12 @@ import random import time -from aios.hooks.stores._global import global_llm_req_queue_add_message +from aios.hooks.stores._global import ( + global_llm_req_queue_add_message, + global_memory_req_queue_add_message, + global_storage_req_queue_add_message, + global_tool_req_queue_add_message, +) class Syscall(Thread): @@ -14,7 +19,7 @@ def __init__(self, agent_name, query): agent_name (str): Name of the agent query (Query): Query sent by the agent """ - super().__init__(name=agent_name) + super().__init__() self.agent_name = agent_name self.query = query self.event = Event() @@ -81,14 +86,6 @@ def set_time_limit(self, time_limit): self.time_limit = time_limit def run(self): - """Response Listener for agent - - Args: - agent_process (AgentProcess): Listened AgentProcess - - Returns: - str: LLM response of Agent Process - """ self.set_pid(self.native_id) self.event.wait() @@ -105,7 +102,162 @@ class StorageSyscall(Syscall): pass +class ToolSyscall(Syscall): + pass + + def send_request(agent_name, query): + action_type = query.action_type + + if action_type == "chat": + return llm_syscall(agent_name, query) + + elif action_type == "tool_use": + return tool_syscall(llm_syscall(agent_name, query)) + + elif action_type == "operate_file": + return storage_syscall(llm_syscall(agent_name, query)) + + elif action_type == "memory_use": + return mem_syscall(agent_name, query) + + elif action_type == "storage_use": + return storage_syscall(agent_name, query) + + +def storage_syscall(agent_name, query): + syscall = StorageSyscall(agent_name, query) + syscall.set_status("active") + + completed_response, start_times, end_times, waiting_times, turnaround_times = ( + "", + [], + [], + [], + [], + ) + while syscall.get_status() != "done": + current_time = time.time() + syscall.set_created_time(current_time) + syscall.set_response(None) + + global_storage_req_queue_add_message(syscall) + + syscall.start() + syscall.join() + + completed_response = syscall.get_response() + + if syscall.get_status() != "done": + pass + start_time = syscall.get_start_time() + end_time = syscall.get_end_time() + waiting_time = start_time - syscall.get_created_time() + turnaround_time = end_time - syscall.get_created_time() + + start_times.append(start_time) + end_times.append(end_time) + waiting_times.append(waiting_time) + turnaround_times.append(turnaround_time) + + return { + "response": completed_response, + "start_times": start_times, + "end_times": end_times, + "waiting_times": waiting_times, + "turnaround_times": turnaround_times, + } + + +def mem_syscall(agent_name, query): + syscall = MemSyscall(agent_name, query) + syscall.set_status("active") + + completed_response, start_times, end_times, waiting_times, turnaround_times = ( + "", + [], + [], + [], + [], + ) + while syscall.get_status() != "done": + current_time = time.time() + syscall.set_created_time(current_time) + syscall.set_response(None) + + global_memory_req_queue_add_message(syscall) + + syscall.start() + syscall.join() + + completed_response = syscall.get_response() + + if syscall.get_status() != "done": + pass + start_time = syscall.get_start_time() + end_time = syscall.get_end_time() + waiting_time = start_time - syscall.get_created_time() + turnaround_time = end_time - syscall.get_created_time() + + start_times.append(start_time) + end_times.append(end_time) + waiting_times.append(waiting_time) + turnaround_times.append(turnaround_time) + + return { + "response": completed_response, + "start_times": start_times, + "end_times": end_times, + "waiting_times": waiting_times, + "turnaround_times": turnaround_times, + } + + +def tool_syscall(agent_name, query): + syscall = ToolSyscall(agent_name, query) + syscall.set_status("active") + + completed_response, start_times, end_times, waiting_times, turnaround_times = ( + "", + [], + [], + [], + [], + ) + while syscall.get_status() != "done": + current_time = time.time() + syscall.set_created_time(current_time) + syscall.set_response(None) + + global_tool_req_queue_add_message(syscall) + + syscall.start() + syscall.join() + + completed_response = syscall.get_response() + + if syscall.get_status() != "done": + pass + start_time = syscall.get_start_time() + end_time = syscall.get_end_time() + waiting_time = start_time - syscall.get_created_time() + turnaround_time = end_time - syscall.get_created_time() + + start_times.append(start_time) + end_times.append(end_time) + waiting_times.append(waiting_time) + turnaround_times.append(turnaround_time) + + return { + "response": completed_response, + "start_times": start_times, + "end_times": end_times, + "waiting_times": waiting_times, + "turnaround_times": turnaround_times, + } + + +def llm_syscall(agent_name, query): syscall = LLMSyscall(agent_name=agent_name, query=query) syscall.set_status("active") @@ -141,10 +293,10 @@ def send_request(agent_name, query): waiting_times.append(waiting_time) turnaround_times.append(turnaround_time) - return ( - completed_response, - start_times, - end_times, - waiting_times, - turnaround_times, - ) + return { + "response": completed_response, + "start_times": start_times, + "end_times": end_times, + "waiting_times": waiting_times, + "turnaround_times": turnaround_times, + } diff --git a/aios/hooks/types/memory.py b/aios/hooks/types/memory.py index 3cc6f6e58..712bf3a99 100644 --- a/aios/hooks/types/memory.py +++ b/aios/hooks/types/memory.py @@ -6,4 +6,9 @@ MemoryRequestQueueGetMessage: TypeAlias = Callable[[], None] MemoryRequestQueueAddMessage: TypeAlias = Callable[[str], None] -MemoryRequestQueueCheckEmpty: TypeAlias = Callable[[], bool] \ No newline at end of file +MemoryRequestQueueCheckEmpty: TypeAlias = Callable[[], bool] + +class MemoryManagerParams(BaseModel): + memory_limit: int + eviction_k: int + storage_manager: Any \ No newline at end of file diff --git a/aios/hooks/types/scheduler.py b/aios/hooks/types/scheduler.py index 5ca67eb30..1205cc3ba 100644 --- a/aios/hooks/types/scheduler.py +++ b/aios/hooks/types/scheduler.py @@ -8,8 +8,11 @@ class SchedulerParams(BaseModel): llm: Any + memory_manager: Any + storage_manager: Any + tool_manager: Any log_mode: str get_llm_request: LLMRequestQueueGetMessage | None get_memory_request: MemoryRequestQueueGetMessage | None - get_storage_request: MemoryRequestQueueGetMessage | None - get_tool_request: MemoryRequestQueueGetMessage | None \ No newline at end of file + get_storage_request: StorageRequestQueueGetMessage | None + get_tool_request: ToolRequestQueueGetMessage | None \ No newline at end of file diff --git a/aios/hooks/types/storage.py b/aios/hooks/types/storage.py index 5cb8d9c6a..8806230a6 100644 --- a/aios/hooks/types/storage.py +++ b/aios/hooks/types/storage.py @@ -6,4 +6,8 @@ StorageRequestQueueGetMessage: TypeAlias = Callable[[], None] StorageRequestQueueAddMessage: TypeAlias = Callable[[str], None] -StorageRequestQueueCheckEmpty: TypeAlias = Callable[[], bool] \ No newline at end of file +StorageRequestQueueCheckEmpty: TypeAlias = Callable[[], bool] + +class StorageManagerParams(BaseModel): + root_dir: str + use_vector_db: bool = False \ No newline at end of file diff --git a/aios/hooks/types/tool.py b/aios/hooks/types/tool.py index 18b8f725e..78d06545c 100644 --- a/aios/hooks/types/tool.py +++ b/aios/hooks/types/tool.py @@ -8,6 +8,6 @@ ToolRequestQueueAddMessage: TypeAlias = Callable[[str], None] ToolRequestQueueCheckEmpty: TypeAlias = Callable[[], bool] -class ToolParams(BaseModel): +class ToolManagerParams(BaseModel): name: str params: dict | None = (None,) \ No newline at end of file diff --git a/aios/hooks/utils.py b/aios/hooks/utils.py new file mode 100644 index 000000000..cd5923fdc --- /dev/null +++ b/aios/hooks/utils.py @@ -0,0 +1,5 @@ +import random +import string + +def generate_random_string(length: int = 6) -> str: + return ''.join(random.choices(string.ascii_letters, k=length)) diff --git a/aios/hooks/validate.py b/aios/hooks/validate.py new file mode 100644 index 000000000..d6c09f2ef --- /dev/null +++ b/aios/hooks/validate.py @@ -0,0 +1,20 @@ +from pydantic import BaseModel, ValidationError +from typing import Callable, Type + +def validate(model_class: Type[BaseModel]): + """ + Decorator factory to validate and parse parameters using a specified Pydantic model. + + :param model_class: The Pydantic model class to validate against + """ + def decorator(func: Callable): + def wrapper(*args, **kwargs): + try: + params = model_class(**kwargs) + + return func(params) + except ValidationError as e: + print(f"Validation error: {e}") + return None + return wrapper + return decorator diff --git a/aios/llm_core/llm_classes/gemini_llm.py b/aios/llm_core/llm_classes/gemini_llm.py index 7c3718fde..6669ea11b 100644 --- a/aios/llm_core/llm_classes/gemini_llm.py +++ b/aios/llm_core/llm_classes/gemini_llm.py @@ -58,9 +58,9 @@ def process(self, agent_request.set_status("executing") agent_request.set_start_time(time.time()) - messages = agent_request.request_data.messages - tools = agent_request.request_data.tools - message_return_type = agent_request.request_data.message_return_type + messages = agent_request.query.messages + tools = agent_request.query.tools + message_return_type = agent_request.query.message_return_type if tools: messages = self.tool_calling_input_format(messages, tools) @@ -113,10 +113,12 @@ def process(self, response = Response( response_message=result, ) + except IndexError: raise IndexError(f"{self.model_name} can not generate a valid result, please try again") # agent_request.set_status("done") # agent_request.set_end_time(time.time()) # return + print(response) return response diff --git a/aios/llm_core/llm_classes/gpt_llm.py b/aios/llm_core/llm_classes/gpt_llm.py index e9c1cb613..89f7f98aa 100644 --- a/aios/llm_core/llm_classes/gpt_llm.py +++ b/aios/llm_core/llm_classes/gpt_llm.py @@ -53,13 +53,13 @@ def process(self, agent_request, temperature=0.0): """ wrapper around openai api """ agent_request.set_status("executing") agent_request.set_start_time(time.time()) - messages = agent_request.request_data.messages + messages = agent_request.query.messages try: response = self.model.chat.completions.create( model=self.model_name, messages=messages, - tools=agent_request.request_data.tools, + tools=agent_request.query.tools, # tool_choice = "required" if agent_request.request_data.tools else None, max_tokens=self.max_new_tokens, ) diff --git a/aios/memory/manager.py b/aios/memory/manager.py new file mode 100644 index 000000000..74abc6195 --- /dev/null +++ b/aios/memory/manager.py @@ -0,0 +1,22 @@ +from .memory_classes.single_memory import SingleMemoryManager + + +class MemoryManager: + def __init__( + self, + memory_limit, + eviction_k, + storage_manager, + log_mode: str = "console", + ): + self.memory_manager = SingleMemoryManager( + memory_limit, + eviction_k, + storage_manager + ) + + def address_request( + self, + agent_request, + ) -> None: + return self.memory_manager.address_request(agent_request) diff --git a/aios/memory/memory_classes/shared_memory.py b/aios/memory/memory_classes/shared_memory.py new file mode 100644 index 000000000..fbd490bad --- /dev/null +++ b/aios/memory/memory_classes/shared_memory.py @@ -0,0 +1,17 @@ +# This file will be an implementation of the shared memory mechanism for +# multi-agent systems + +from aios.memory.base import BaseMemory + +''' +TODO: implement the shared memory mechanism +''' +class SharedMemory(BaseMemory): + def __init__(self): + pass + + def save(self): + pass + + def load(self): + pass diff --git a/aios/memory/memory_classes/single_memory.py b/aios/memory/memory_classes/single_memory.py new file mode 100644 index 000000000..0912ff776 --- /dev/null +++ b/aios/memory/memory_classes/single_memory.py @@ -0,0 +1,66 @@ +from aios.memory.base import ( + MemoryRequest, + BaseMemoryManager +) + +from typing import Dict, OrderedDict + +import pickle +import zlib + +from threading import Thread + +class SingleMemoryManager: + def __init__(self, + memory_limit, + eviction_k, + storage_manager): + self.memory_blocks = dict() + self.memory_limit = memory_limit + self.eviction_k = eviction_k + self.storage_manager = storage_manager + + def address_request(self, agent_request): + operation_type = agent_request.operation_type + if operation_type == "allocate": + self.mem_alloc() + + def mem_alloc(self, aid): + if aid not in self.memory_blocks: + self.memory_blocks[aid] = OrderedDict() + self.storage_manager.sto_create(aid) + + def mem_read(self, aid, rid): + if aid in self.memory_blocks and rid in self.memory_blocks[aid]: + compressed_data = self.memory_blocks[aid].pop(rid) + self.memory_blocks[aid][rid] = compressed_data + return pickle.loads(zlib.decompress(compressed_data)) + else: + return self.storage_manager.sto_read(aid, rid) + + def mem_write(self, aid, rid, s): + self.mem_alloc(aid) + serialized_data = pickle.dumps(s) + compressed_data = zlib.compress(serialized_data) + + if rid in self.memory_blocks[aid]: + self.memory_blocks[aid].pop(rid) + self.memory_blocks[aid][rid] = compressed_data + + if self._total_memory_count() > self.memory_limit: + self._evict_memory(aid) + + def mem_clear(self, aid): + if aid in self.memory_blocks: + del self.memory_blocks[aid] + self.storage_manager.sto_clear(aid) + + def _total_memory_count(self): + return sum(len(blocks) for blocks in self.memory_blocks.values()) + + def _evict_memory(self, aid): + if aid in self.memory_blocks: + for _ in range(min(self.eviction_k, + len(self.memory_blocks[aid]))): + rid, compressed_data = self.memory_blocks[aid].popitem(last=False) + self.storage_manager.sto_write(aid, rid, pickle.loads(zlib.decompress(compressed_data))) diff --git a/aios/scheduler/fifo_scheduler.py b/aios/scheduler/fifo_scheduler.py index 03f9b0d1c..1947ef36e 100644 --- a/aios/scheduler/fifo_scheduler.py +++ b/aios/scheduler/fifo_scheduler.py @@ -29,7 +29,7 @@ def __init__( get_storage_request: StorageRequestQueueGetMessage, get_tool_request: ToolRequestQueueGetMessage, ): - self.agent_process_queue = Queue() + # self.agent_process_queue = Queue() self.get_llm_request = get_llm_request self.get_memory_request = get_memory_request self.get_storage_request = get_storage_request @@ -79,8 +79,6 @@ def run_llm_request(self): response = self.llm.address_request(agent_request) agent_request.set_response(response) - # self.llm.address_request(agent_request) - agent_request.event.set() agent_request.set_status("done") agent_request.set_end_time(time.time()) diff --git a/aios/storage/storage.py b/aios/storage/storage.py new file mode 100644 index 000000000..a31abade5 --- /dev/null +++ b/aios/storage/storage.py @@ -0,0 +1,84 @@ +import os + +import pickle + +import zlib + +from .storage_classes.db_storage import ChromaDB + +class StorageManager: + def __init__(self, root_dir, use_vector_db=False): + self.root_dir = root_dir + os.makedirs(self.root_dir, exist_ok=True) + if use_vector_db: + self.vector_db = ChromaDB() + + def address_request(self, agent_request): + operation_type = agent_request.operation_type + if operation_type == "create": + self.sto_create(agent_request.agent_name) + elif operation_type == "write": + self.sto_write(agent_request.agent_name, s=agent_request.prompt) + elif operation_type == "read": + return self.sto_read(agent_request.agent_name) + elif operation_type == "clear": + self.sto_clear(agent_request.agent_name) + elif operation_type == "retrieve": + return self.sto_retrieve( + agent_request.agent_name, query=agent_request.prompt + ) + + def sto_create(self, aname, aid=None, rid=None): + file_path = os.path.join( + self.storage_path, f"{aid}_{rid}.dat" if aid and rid else f"{aname}.dat" + ) + + if not os.path.exists(file_path): + with open(file_path, "wb") as file: + file.write(b"") + if self.use_vector_db: + self.vector_db.create_collection(f"{aid}_{rid}" if aid and rid else aname) + + def sto_read(self, aname, aid=None, rid=None): + file_path = os.path.join( + self.storage_path, f"{aid}_{rid}.dat" if aid and rid else f"{aname}.dat" + ) + + if os.path.exists(file_path): + with open(file_path, "rb") as file: + compressed_data = file.read() + return ( + pickle.loads(zlib.decompress(compressed_data)) + if compressed_data + else None + ) + return None + + def sto_write(self, aname, s, aid=None, rid=None): + """Writes compressed data to a storage file and adds it to the vector database""" + file_path = os.path.join( + self.storage_path, f"{aid}_{rid}.dat" if aid and rid else f"{aname}.dat" + ) + + with open(file_path, "ab") as file: + compressed_data = zlib.compress(pickle.dumps(s)) + file.write(compressed_data) + if self.use_vector_db: + self.vector_db.add(f"{aid}_{rid}" if aid and rid else aname, s) + + def sto_clear(self, aname, aid=None, rid=None): + file_path = os.path.join( + self.storage_path, f"{aid}_{rid}.dat" if aid and rid else f"{aname}.dat" + ) + + if os.path.exists(file_path): + os.remove(file_path) + if self.use_vector_db: + self.vector_db.delete(f"{aid}_{rid}" if aid and rid else aname) + + def sto_retrieve(self, aname, query, aid=None, rid=None): + if self.use_vector_db: + return self.vector_db.retrieve( + f"{aid}_{rid}" if aid and rid else aname, query + ) + return None diff --git a/aios/storage/storage_classes/db_storage.py b/aios/storage/storage_classes/db_storage.py new file mode 100644 index 000000000..5c7166642 --- /dev/null +++ b/aios/storage/storage_classes/db_storage.py @@ -0,0 +1,82 @@ +from chromadb.config import Settings +from watchdog.observers import Observer +from watchdog.events import FileSystemEventHandler + +import os + +import chromadb + +from llama_index.embeddings.huggingface import HuggingFaceEmbedding + +from llama_index.core import VectorStoreIndex, SimpleDirectoryReader + +class ChromaDB: + def __init__(self, mount_dir) -> None: + super().__init__() + self.mount_dir = mount_dir + # self.build_database() + + self.client = chromadb.PersistentClient(self.mount_dir) + + def add_collection(self, collection_name): + collection_name = os.path.join(os.path.basename(self.mount_dir), collection_name) + self.client.get_or_create_collection(name=collection_name) + + # add collection + def build_database(self): + for subdir, _, files in os.walk(self.mount_dir): + for f in files: + file_path = os.path.join(subdir, f) + file_name = os.path.splitext(f)[0] + if file_name == ".DS_Store": + continue + self.add_or_update_file_in_collection(file_path, file_name) + + def add_or_update_file_in_collection(self, file_path, file_name): + """ + Adds or updates the file's content in the specified collection. + - client: PersistentClient object + - collection_name: Name of the collection (filename without extension) + - file_path: Path to the file to be added or updated + """ + documents = SimpleDirectoryReader(input_files=[file_path]).load_data() + content = " ".join([doc.text for doc in documents]) + + existing_docs = self.collection.get(ids=[file_name]) + + if existing_docs["ids"]: + doc_id = existing_docs["ids"] + self.collection.update( + documents=[content], + ids=doc_id, + metadatas=[{"file_path": file_path, "file_name": file_name}], + ) + else: + # doc_id = str(uuid.uuid4()) + self.collection.add( + documents=[content], + ids=[file_name], + metadatas=[{"file_path": file_path, "file_name": file_name}], + ) + + def delete_file_from_collection(self, client, collection_name, file_path): + """ + Removes the file's document from the specified collection. + - client: PersistentClient object + - collection_name: Name of the collection (filename without extension) + - file_path: Path to the file that was deleted + """ + collection = client.get_or_create_collection(name=collection_name) + + existing_docs = collection.get(ids=[file_path]) + + if existing_docs["ids"]: + # print(f"Deleting document for file: {file_path}") + collection.delete(ids=[file_path]) + else: + print(f"No document found for deleted file: {file_path}") + + def retrieve(self, name, k, keywords): + results = self.collection.query(query_texts=[keywords], n_results=int(k)) + print([doc[:500] for doc in results["documents"][0]]) + print(results["metadatas"]) \ No newline at end of file diff --git a/aios/tool/manager.py b/aios/tool/manager.py new file mode 100644 index 000000000..d3e1ccace --- /dev/null +++ b/aios/tool/manager.py @@ -0,0 +1,38 @@ +import importlib + +class ToolManager: + def __init__( + self, + log_mode: str = "console", + ): + self.log_mode = log_mode + self.tool_conflict_map = {} + + def address_request(self, syscall) -> None: + request_data = syscall.request_data + tool_org_and_name, tool_params = ( + request_data["name"], + request_data["paramemters"], + ) + # org, tool_name = tool_org_and_name.split("/") + + if tool_org_and_name not in self.tool_conflict_map.keys(): + self.tool_conflict_map[tool_org_and_name] = 1 + tool_class = self.load_tool_instance(tool_org_and_name) + + tool = tool_class(tool_name=tool_org_and_name) + tool.run(params=tool_params) + + self.tool_conflict_map.pop(tool_org_and_name) + + def snake_to_camel(self, snake_str): + components = snake_str.split("_") + return "".join(x.title() for x in components) + + def load_tool_instance(self, tool_org_and_name): + org, tool_name = tool_org_and_name.split("/") + module_name = ".".join(["pyopenagi", "tools", org, tool_name]) + class_name = self.snake_to_camel(tool_name) + tool_module = importlib.import_module(module_name) + tool_instance = getattr(tool_module, class_name) + return tool_instance diff --git a/experiment/agent/experiment_agent.py b/experiment/agent/experiment_agent.py index 32c6a0470..5ebac3575 100644 --- a/experiment/agent/experiment_agent.py +++ b/experiment/agent/experiment_agent.py @@ -1,17 +1,17 @@ from abc import ABC, abstractmethod from aios.hooks.syscall import send_request -from pyopenagi.utils.chat_template import Query +from pyopenagi.utils.chat_template import LLMQuery, MemoryQuery, StorageQuery -class ExpirementAgent(ABC): +class ExperimentAgent(ABC): @abstractmethod def run(self, input_str: str): pass -class SimpleLLMAgent(ExpirementAgent): +class SimpleLLMAgent(ExperimentAgent): def __init__(self, on_aios: bool = True): self.agent_name = "gpt" @@ -19,7 +19,7 @@ def __init__(self, on_aios: bool = True): def run(self, input_str: str): message = {"content": input_str, "role": "user"} - query = Query(messages=[message], tools=None) + query = LLMQuery(messages=[message], tools=None) response, _, _, _, _ = send_request( agent_name=self.agent_name, diff --git a/pyopenagi/agents/example/academic_agent/agent.py b/pyopenagi/agents/example/academic_agent/agent.py index 59b29cf6e..9f61a8f46 100644 --- a/pyopenagi/agents/example/academic_agent/agent.py +++ b/pyopenagi/agents/example/academic_agent/agent.py @@ -5,18 +5,19 @@ from aios.hooks.syscall import send_request -from pyopenagi.utils.chat_template import Query +from pyopenagi.utils.chat_template import LLMQuery, MemoryQuery, StorageQuery from pyopenagi.utils.logger import AgentLogger import json + class AcademicAgent: def __init__(self, agent_name, task_input, log_mode: str): self.agent_name = agent_name self.config = self.load_config() self.tool_names = self.config["tools"] - + self.plan_max_fail_times = 3 self.tool_call_max_fail_times = 3 @@ -42,89 +43,64 @@ def __init__(self, agent_name, task_input, log_mode: str): self.log_mode = log_mode self.logger = self.setup_logger() - self.set_status("active") self.set_created_time(time.time()) - def check_path(self, tool_calls): + + def setup_logger(self): + logger = AgentLogger(self.agent_name, self.log_mode) + return logger + + def load_config(self): script_path = os.path.abspath(__file__) - save_dir = os.path.join( - os.path.dirname(script_path), "output" - ) # modify the customized output path for saving outputs - if not os.path.exists(save_dir): - os.makedirs(save_dir) - for tool_call in tool_calls: - try: - for k in tool_call["parameters"]: - if "path" in k: - path = tool_call["parameters"][k] - if not path.startswith(save_dir): - tool_call["parameters"][k] = os.path.join( - save_dir, os.path.basename(path) - ) - except Exception: - continue - return tool_calls + script_dir = os.path.dirname(script_path) + config_file = os.path.join(script_dir, self.agent_name, "config.json") + with open(config_file, "r") as f: + config = json.load(f) + return config def build_system_instruction(self): - prefix = "".join( - [ - "".join(self.config["description"]) - ] - ) + prefix = "".join(["".join(self.config["description"])]) plan_instruction = "".join( [ - f'You are given the available tools from the tool list: {json.dumps(self.tool_info)} to help you solve problems. ', - 'Generate a plan with comprehensive yet minimal steps to fulfill the task. ', - 'The plan must follow the json format as below: ', - '[', + f"You are given the available tools from the tool list: {json.dumps(self.tool_info)} to help you solve problems. ", + "Generate a plan with comprehensive yet minimal steps to fulfill the task. ", + "The plan must follow the json format as below: ", + "[", '{"message": "message_value1","tool_use": [tool_name1, tool_name2,...]}', '{"message": "message_value2", "tool_use": [tool_name1, tool_name2,...]}', - '...', - ']', - 'In each step of the planned plan, identify tools to use and recognize no tool is necessary. ', - 'Followings are some plan examples. ', - '[' - '[', + "...", + "]", + "In each step of the planned plan, identify tools to use and recognize no tool is necessary. ", + "Followings are some plan examples. ", + "[" "[", '{"message": "gather information from arxiv. ", "tool_use": ["arxiv"]},', '{"message", "write a summarization based on the gathered information. ", "tool_use": []}', - '];', - '[', + "];", + "[", '{"message": "gather information from arxiv. ", "tool_use": ["arxiv"]},', '{"message", "understand the current methods and propose ideas that can improve ", "tool_use": []}', - ']', - ']' + "]", + "]", ] ) if self.workflow_mode == "manual": - self.messages.append( - {"role": "system", "content": prefix} - ) + self.messages.append({"role": "system", "content": prefix}) else: assert self.workflow_mode == "automatic" - self.messages.append( - {"role": "system", "content": prefix} - ) - self.messages.append( - {"role": "user", "content": plan_instruction} - ) - + self.messages.append({"role": "system", "content": prefix}) + self.messages.append({"role": "user", "content": plan_instruction}) + def automatic_workflow(self): for i in range(self.plan_max_fail_times): - response, start_times, end_times, waiting_times, turnaround_times = send_request( - agent_name = self.agent_name, - query=Query( + response = send_request( + agent_name=self.agent_name, + query=LLMQuery( messages=self.messages, tools=None, message_return_type="json" - ) - ) - - if self.rounds == 0: - self.set_start_time(start_times[0]) - - self.request_waiting_times.extend(waiting_times) - self.request_turnaround_times.extend(turnaround_times) + ), + )["response"] workflow = self.check_workflow(response.response_message) @@ -141,47 +117,22 @@ def automatic_workflow(self): } ) return None - + def manual_workflow(self): workflow = [ { - "action_type": "message_llm", + "action_type": "chat", "action": "Search for relevant papers", "tool_use": ["arxiv"], }, { - "action_type": "message_llm", + "action_type": "tool_use", "action": "Provide responses based on the user's query", "tool_use": [], - } + }, ] return workflow - def call_tools(self, tool_calls): - # self.logger.log(f"***** It starts to call external tools *****\n", level="info") - success = True - actions = [] - observations = [] - - # print(tool_calls) - for tool_call in tool_calls: - # print(tool_call) - function_name = tool_call["name"] - function_to_call = self.tool_list[function_name] - function_params = tool_call["parameters"] - - try: - function_response = function_to_call.run(function_params) - actions.append(f"I will call the {function_name} with the params as {function_params}") - observations.append(f"The output of calling the {function_name} tool is: {function_response}") - - except Exception: - actions.append("I fail to call any tools.") - observations.append(f"The tool parameter {function_params} is invalid.") - success = False - - return actions, observations, success - def run(self): self.build_system_instruction() @@ -194,12 +145,12 @@ def run(self): if self.workflow_mode == "automatic": workflow = self.automatic_workflow() + self.messages = self.messages[:1] # clear long context + else: assert self.workflow_mode == "manual" workflow = self.manual_workflow() - self.messages = self.messages[:1] # clear long context - self.messages.append( { "role": "user", @@ -207,13 +158,6 @@ def run(self): } ) - # if workflow: - # self.logger.log(f"Generated workflow is: {workflow}\n", level="info") - # else: - # self.logger.log( - # "Fail to generate a valid workflow. Invalid JSON?\n", level="info" - # ) - try: if workflow: final_result = "" @@ -225,72 +169,21 @@ def run(self): prompt = f"At step {i + 1}, you need to: {action}. " self.messages.append({"role": "user", "content": prompt}) - + if tool_use: selected_tools = self.pre_select_tools(tool_use) else: selected_tools = None - ( - response, - start_times, - end_times, - waiting_times, - turnaround_times, - ) = send_request( + response = send_request( agent_name=self.agent_name, - query=Query( + query=LLMQuery( messages=self.messages, tools=selected_tools, action_type=action_type, - ) - ) - - if self.rounds == 0: - self.set_start_time(start_times[0]) - - # execute action - response_message = response.response_message - - tool_calls = response.tool_calls - - self.request_waiting_times.extend(waiting_times) - self.request_turnaround_times.extend(turnaround_times) - - if tool_calls: - for _ in range(self.plan_max_fail_times): - tool_calls = self.check_path(tool_calls) - actions, observations, success = self.call_tools( - tool_calls=tool_calls - ) - - action_messages = "[Action]: " + ";".join(actions) - observation_messages = "[Observation]: " + ";".join( - observations - ) - - self.messages.append( - { - "role": "assistant", - "content": action_messages - + ". " - + observation_messages, - } - ) - if success: - break - else: - thinkings = response_message - self.messages.append( - {"role": "assistant", "content": thinkings} - ) - - if i == len(workflow) - 1: - final_result = self.messages[-1] - - step_result = self.messages[-1]["content"] - self.logger.log(f"At step {i + 1}, {step_result}\n", level="info") + ), + )["response"] self.rounds += 1 @@ -317,90 +210,7 @@ def run(self): "request_waiting_times": self.request_waiting_times, "request_turnaround_times": self.request_turnaround_times, } + except Exception as e: print(e) return {} - - def snake_to_camel(self, snake_str): - components = snake_str.split("_") - return "".join(x.title() for x in components) - - def load_tools(self, tool_names): - if tool_names == "None": - return - - for tool_name in tool_names: - org, name = tool_name.split("/") - module_name = ".".join(["pyopenagi", "tools", org, name]) - class_name = self.snake_to_camel(name) - - tool_module = importlib.import_module(module_name) - tool_class = getattr(tool_module, class_name) - - self.tool_list[name] = tool_class() - tool_format = tool_class().get_tool_call_format() - self.tools.append(tool_format) - self.tool_info.append( - { - "name": tool_format["function"]["name"], - "description": tool_format["function"]["description"], - } - ) - - def pre_select_tools(self, tool_names): - pre_selected_tools = [] - for tool_name in tool_names: - for tool in self.tools: - if tool["function"]["name"] == tool_name: - pre_selected_tools.append(tool) - break - - return pre_selected_tools - - def setup_logger(self): - logger = AgentLogger(self.agent_name, self.log_mode) - return logger - - def load_config(self): - script_path = os.path.abspath(__file__) - script_dir = os.path.dirname(script_path) - config_file = os.path.join(script_dir, "config.json") - with open(config_file, "r") as f: - config = json.load(f) - return config - - def set_aid(self, aid): - self.aid = aid - - def get_aid(self): - return self.aid - - def get_agent_name(self): - return self.agent_name - - def set_status(self, status): - """ - Status type: Waiting, Running, Done, Inactive - """ - self.status = status - - def get_status(self): - return self.status - - def set_created_time(self, time): - self.created_time = time - - def get_created_time(self): - return self.created_time - - def set_start_time(self, time): - self.start_time = time - - def get_start_time(self): - return self.start_time - - def set_end_time(self, time): - self.end_time = time - - def get_end_time(self): - return self.end_time \ No newline at end of file diff --git a/pyopenagi/agents/experiment/standard/__init__.py b/pyopenagi/agents/experiment/standard/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyopenagi/agents/experiment/standard/action/__init__.py b/pyopenagi/agents/experiment/standard/action/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyopenagi/agents/experiment/standard/action/action.py b/pyopenagi/agents/experiment/standard/action/action.py new file mode 100644 index 000000000..56b62c265 --- /dev/null +++ b/pyopenagi/agents/experiment/standard/action/action.py @@ -0,0 +1,12 @@ +from abc import ABC, abstractmethod + + +class Action(ABC): + + @abstractmethod + def __call__(self, *args, **kwargs): + pass + + @abstractmethod + def format_prompt(self): + pass diff --git a/pyopenagi/agents/experiment/standard/action/action_code.py b/pyopenagi/agents/experiment/standard/action/action_code.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyopenagi/agents/experiment/standard/action/action_tool.py b/pyopenagi/agents/experiment/standard/action/action_tool.py new file mode 100644 index 000000000..af432bb9d --- /dev/null +++ b/pyopenagi/agents/experiment/standard/action/action_tool.py @@ -0,0 +1,60 @@ +import importlib +from typing import List, Any, Optional +from pydantic.v1 import BaseModel, root_validator +from pyopenagi.agents.experiment.standard.action.action import Action +from pyopenagi.agents.experiment.standard.utils.config import Config +from pyopenagi.agents.experiment.standard.utils.str_utils import snake_to_camel + + +class ActionTool(Action, BaseModel): + + config: Config + tools: Optional[List] + tools_format: Optional[List] + type: str = "TOOL" + + def __call__(self, tool_call: dict) -> Any: + if tool_call is None: + return + + function_name = tool_call["name"] + function_param = tool_call["parameters"] + try: + function_call = self.tools[function_name] + function_response = function_call.run(function_param) + + except TypeError: + function_response = f"Call function {function_name} failed. Parameters {function_param} is invalid." + + return function_response + + @root_validator(pre=True) + def init_tools(self): + self._init_tools_from_config() + + def _init_tools_from_config(self): + tool_names = self.config.tools + if tool_names == "None": + return + + for tool_name in tool_names: + org, name = tool_name.split("/") + module_name = ".".join(["pyopenagi", "tools", org, name]) + class_name = snake_to_camel(name) + + tool_module = importlib.import_module(module_name) + tool_class = getattr(tool_module, class_name) + + self.tools[name] = tool_class() + tool_format = tool_class().get_tool_call_format() + self.tools_format.append(tool_format) + + def format_prompt(self): + return { + "name": "tool use", + "description": "" + } + + @staticmethod + def display(): + return False diff --git a/pyopenagi/agents/experiment/standard/agent.py b/pyopenagi/agents/experiment/standard/agent.py new file mode 100644 index 000000000..624a7f333 --- /dev/null +++ b/pyopenagi/agents/experiment/standard/agent.py @@ -0,0 +1,157 @@ +import time +from typing import List +from aios.hooks.request import send_request +from pyopenagi.agents.experiment.standard.action.action_tool import ActionTool +from pyopenagi.agents.experiment.standard.memory.short_term_memory import ShortTermMemory +from pyopenagi.agents.experiment.standard.planning.planning import Planning, DefaultPlanning +from pyopenagi.agents.experiment.standard.prompt.framework_prompt import STANDARD_PROMPT +from pyopenagi.agents.experiment.standard.utils.config import load_config +from pyopenagi.utils.chat_template import Query, Response +from pyopenagi.utils.logger import AgentLogger + + +class StandardAgent: + + def __init__(self, agent_name: str, task_input: str, log_mode: str): + # Init module + self.planning: Planning | None = None + self.actions = {} + self.communication = None + self.memory = None + self.short_term_memory = ShortTermMemory() + + # Init config and tool + self.config = load_config() + + # Init agent base info + self.agent_name = agent_name + self.task_input = task_input + self._init_framework_prompt() + + # Init logger + self.logger = AgentLogger(agent_name, log_mode) + + # Init AIOS monitor info + self.rounds = 0 + self.status = "active" + self.start_time = None + self.end_time = None + self.request_waiting_times: list = [] + self.request_turnaround_times: list = [] + self.created_time = time.time() + + @property + def messages(self): + return self.short_term_memory.messages + + @property + def tools_format(self): + if "TOOL" in self.actions: + return self.actions["TOOL"].tools_format + else: + return None + + def custom_prompt(self) -> str: + pass + + def _init_framework_prompt(self): + # Action + action_prompt = self._action_prompt() + planning_prompt = self._planning_prompt() + + framework_prompt = STANDARD_PROMPT.format( + action=action_prompt, + planning=planning_prompt, + ) + + self.short_term_memory.remember(role="system", content=framework_prompt) + + def _action_prompt(self) -> str: + action_prompt = "" + for action in self.actions: + if action.disply: + name = action.format_prompt()["name"] + description = action.format_prompt()["description"] + action_prompt += f"- {name}: {description}\n" + + return action_prompt + + def _planning_prompt(self) -> str: + planning_prompt = "" + + name = self.planning.format_prompt()["name"] + description = self.planning.format_prompt()["description"] + planning_prompt += f"- {name}: {description}\n" + return planning_prompt + + def init_module(self): + return + + def init_planning(self, planning): + self.planning = planning + + def init_communication(self, communication): + return + + def init_memory(self, memory): + return + + def init_actions(self, actions): + action_tool = ActionTool() + self.actions[action_tool.type] = action_tool + + def planning(self) -> dict: + # Select suitable messages + messages = self.short_term_memory.recall() + + planning = DefaultPlanning(self.request) + result = planning(messages, self.tools_format) + + return result + + def run(self): + # Init system prompt and task + if custom_prompt := self.custom_prompt(): + self.short_term_memory.remember("system", custom_prompt) + self.short_term_memory.remember("user", self.task_input) + + while not self._is_terminate(): + # Run planning + planning_result = self.planning() + if action_type := planning_result.action_type: + action = self.actions[action_type] + action_param = planning_result.action_param + response, tool_call_id = action(**action_param) + self.short_term_memory.remember("assistant", response, tool_call_id) + else: + response = planning_result.text_content + self.short_term_memory.remember("assistant", response) + + def _is_terminate(self): + return True if "TERMINATE" in self.short_term_memory.last_message else False + + def request(self, messages: List, tools: List) -> Response: + ( + response, + start_times, + end_times, + waiting_times, + turnaround_times + ) = send_request( + agent_name=self.agent_name, + query=Query( + messages=messages, + tools=tools, + action_type="message_llm", + ) + ) + + # Update AIOS monitor info + if self.rounds == 0: + self.start_time = start_times[0] + + self.request_waiting_times.extend(waiting_times) + self.request_turnaround_times.extend(turnaround_times) + self.rounds += 1 + + return response diff --git a/pyopenagi/agents/experiment/standard/communication/__init__.py b/pyopenagi/agents/experiment/standard/communication/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyopenagi/agents/experiment/standard/communication/communication.py b/pyopenagi/agents/experiment/standard/communication/communication.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyopenagi/agents/experiment/standard/config.json b/pyopenagi/agents/experiment/standard/config.json new file mode 100644 index 000000000..6f4aba03a --- /dev/null +++ b/pyopenagi/agents/experiment/standard/config.json @@ -0,0 +1,18 @@ +{ + "name": "standard_agent", + "description": [ + + ], + "tools": [ + + ], + "meta": { + "author": "example", + "version": "0.0.1", + "license": "CC0" + }, + "build": { + "entry": "agent.py", + "module": "StandardAgent" + } +} diff --git a/pyopenagi/agents/experiment/standard/memory/__init__.py b/pyopenagi/agents/experiment/standard/memory/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyopenagi/agents/experiment/standard/memory/memory.py b/pyopenagi/agents/experiment/standard/memory/memory.py new file mode 100644 index 000000000..9469f855b --- /dev/null +++ b/pyopenagi/agents/experiment/standard/memory/memory.py @@ -0,0 +1,2 @@ +class MemoryStandard: + ... diff --git a/pyopenagi/agents/experiment/standard/memory/short_term_memory.py b/pyopenagi/agents/experiment/standard/memory/short_term_memory.py new file mode 100644 index 000000000..db4be8ac8 --- /dev/null +++ b/pyopenagi/agents/experiment/standard/memory/short_term_memory.py @@ -0,0 +1,23 @@ +from typing import List +from pydantic.v1 import BaseModel + + +class ShortTermMemory(BaseModel): + messages: List = [] + + def remember(self, role: str, content: str, tool_call_id: int = None) -> None: + if tool_call_id: + message = {"role": role, "content": content, "tool_call_id": tool_call_id} + self.messages += message + else: + message = {"role": role, "content": content} + self.messages += message + + def recall(self): + return self.messages + + def last_message(self): + return self.messages[-1] + + def clear(self) -> None: + self.messages = [] diff --git a/pyopenagi/agents/experiment/standard/planning/__init__.py b/pyopenagi/agents/experiment/standard/planning/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyopenagi/agents/experiment/standard/planning/planning.py b/pyopenagi/agents/experiment/standard/planning/planning.py new file mode 100644 index 000000000..c1fad557f --- /dev/null +++ b/pyopenagi/agents/experiment/standard/planning/planning.py @@ -0,0 +1,49 @@ +from abc import ABC, abstractmethod +from typing import List, Callable, Optional, Any + +from pydantic.v1 import BaseModel + +from pyopenagi.utils.chat_template import Response + + +class PlanningResult(BaseModel): + text_content: Optional[str] + action_type: Optional[str] + action_param: Optional[Any] + + +class Planning(ABC): + + @abstractmethod + def __call__(self, *args, **kwargs): + pass + + @abstractmethod + def format_prompt(self): + pass + + +class DefaultPlanning(Planning): + + def __init__(self, request_func: Callable[[List, List], Response]): + self.request_func = request_func + + def __call__(self, messages: List, tools: List): + response = self.request_func(messages, tools) + + response_message = response.response_message + tool_calls = response.tool_calls + + result = PlanningResult() + result.text_content = response_message + if tool_calls: + result.action_type = "TOOL" + result.action_param = tool_calls[0] + + return result + + def format_prompt(self): + return { + "name": "normal", + "description": "Planning as normal." + } diff --git a/pyopenagi/agents/experiment/standard/prompt/__init__.py b/pyopenagi/agents/experiment/standard/prompt/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyopenagi/agents/experiment/standard/prompt/framework_prompt.py b/pyopenagi/agents/experiment/standard/prompt/framework_prompt.py new file mode 100644 index 000000000..8b8290606 --- /dev/null +++ b/pyopenagi/agents/experiment/standard/prompt/framework_prompt.py @@ -0,0 +1,30 @@ +STANDARD_PROMPT = """ + +You are a standard agent. You hava four modules: +- Action: The Planning module guides you on how to answer questions. + Please follow the instructions provided by the Planning module strictly when responding to questions. +- Memory: +- Planning: The Planning module guides you on how to answer questions. + Please follow the instructions provided by the Planning module strictly when responding to questions. +- Communication: The Communication module provides the means for you to interact with other agents. + Follow the prompts from the Communication module to communicate and collaborate with other agents. +The following will explain the functions of the modules and how to use them. + + + +{action} + + + +{planning} + + + +{memory} + + + +{communication} + + +""" diff --git a/pyopenagi/agents/experiment/standard/utils/__init__.py b/pyopenagi/agents/experiment/standard/utils/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyopenagi/agents/experiment/standard/utils/config.py b/pyopenagi/agents/experiment/standard/utils/config.py new file mode 100644 index 000000000..affb223df --- /dev/null +++ b/pyopenagi/agents/experiment/standard/utils/config.py @@ -0,0 +1,25 @@ +import json +import os +from typing import List + +from pydantic.v1 import BaseModel + + +class Config(BaseModel): + name: str + description: List + tools: List + meta: dict + build: dict + + +def load_config(): + script_path = os.path.abspath(__file__) + script_dir = os.path.dirname( + os.path.dirname(script_path) + ) + config_file = os.path.join(script_dir, "config.json") + with open(config_file, "r") as f: + data = json.load(f) + + return Config(**data) diff --git a/pyopenagi/agents/experiment/standard/utils/str_utils.py b/pyopenagi/agents/experiment/standard/utils/str_utils.py new file mode 100644 index 000000000..17663ec6d --- /dev/null +++ b/pyopenagi/agents/experiment/standard/utils/str_utils.py @@ -0,0 +1,3 @@ +def snake_to_camel(snake_str): + components = snake_str.split("_") + return "".join(x.title() for x in components) diff --git a/pyopenagi/queues/base_queue.py b/pyopenagi/queues/base_queue.py new file mode 100644 index 000000000..377f69319 --- /dev/null +++ b/pyopenagi/queues/base_queue.py @@ -0,0 +1,17 @@ +import queue + +class BaseQueue: + + _queue = queue.Queue() + + @classmethod + def add_message(cls, message): + cls._queue.put(message) + + @classmethod + def get_message(cls): + return cls._queue.get(block=True, timeout=1) + + @classmethod + def is_empty(cls): + return cls._queue.empty() diff --git a/pyopenagi/queues/llm_request_queue.py b/pyopenagi/queues/llm_request_queue.py new file mode 100644 index 000000000..3555f5cb1 --- /dev/null +++ b/pyopenagi/queues/llm_request_queue.py @@ -0,0 +1,4 @@ +from .base_queue import BaseQueue + +class LLMRequestQueue(BaseQueue): + pass diff --git a/pyopenagi/utils/chat_template.py b/pyopenagi/utils/chat_template.py index 285b46427..3cd908543 100755 --- a/pyopenagi/utils/chat_template.py +++ b/pyopenagi/utils/chat_template.py @@ -2,7 +2,7 @@ from typing import List, Dict, Optional, Any, Union from typing_extensions import Literal # Import Literal from typing_extensions for stricter typing -class Query(BaseModel): +class LLMQuery(BaseModel): """ Query class represents the input structure for performing various actions. @@ -17,11 +17,29 @@ class Query(BaseModel): """ messages: List[Dict[str, Union[str, Any]]] # List of message dictionaries, each containing role and content. tools: Optional[List[Dict[str, Any]]] = Field(default_factory=list) # List of JSON-like objects (dictionaries) representing tools. - action_type: Literal["message_llm", "call_tool", "operate_file"] = Field(default="message_llm") # Restrict the action_type to specific choices. + action_type: Literal["chat", "tool_use", "operate_file"] = Field(default="chat") # Restrict the action_type to specific choices. message_return_type: str = Field(default="text") # Type of the return message, default is "text". class Config: arbitrary_types_allowed = True # Allows the use of arbitrary types such as Any and Dict. + + +class MemoryQuery(BaseModel): + # messages: List[Dict[str, Union[str, Any]]] # List of message dictionaries, each containing role and content. + # message_return_type: str = Field(default="text") # Type of the return message, default is "text". + messages: List[Dict[str, Union[str, Any]]] + operation_type: str + + class Config: + arbitrary_types_allowed = True # Allows the use of arbitrary types such as Any and Dict. + + +class StorageQuery(BaseModel): + messages: List[Dict[str, Union[str, Any]]] # List of message dictionaries, each containing role and content. + operation_type: str = Field(default="text") # Type of the return message, default is "text". + + class Config: + arbitrary_types_allowed = True # Allows the use of arbitrary types such as Any and Dict. class Response(BaseModel): diff --git a/standard_main.py b/standard_main.py new file mode 100644 index 000000000..4aab0d7cb --- /dev/null +++ b/standard_main.py @@ -0,0 +1,30 @@ +import os +from aios.hooks.llm import aios_starter +from aios.utils.utils import parse_global_args + + +def main(**kargs): + main_id = os.getpid() + print(f"Main ID is: {main_id}") + + with aios_starter(**kargs) as (submit_agent, await_agent_execution): + + agent_tasks = [ + ["experiment/standard", "Where is China?"] + ] + + agent_ids = [] + for agent_name, task_input in agent_tasks: + agent_id = submit_agent(agent_name=agent_name, task_input=task_input) + agent_ids.append(agent_id) + + for agent_id in agent_ids: + result = await_agent_execution(agent_id) + print(f"Agent_id: {agent_id} Result: {result}") + + +if __name__ == '__main__': + parser = parse_global_args() + args = parser.parse_args() + + main(**vars(args)) From ba90958af517d21caaa7f7570331f35469c652c5 Mon Sep 17 00:00:00 2001 From: dongyuanjushi Date: Tue, 5 Nov 2024 23:02:37 -0500 Subject: [PATCH 30/41] update --- aios/hooks/syscall.py | 22 +++--- aios/llm_core/llm_classes/gemini_llm.py | 1 - aios/scheduler/fifo_scheduler.py | 34 ++++----- aios/tool/manager.py | 38 +++++----- .../agents/example/academic_agent/agent.py | 70 ++++++++++++++----- pyopenagi/tools/arxiv/arxiv.py | 2 +- pyopenagi/utils/utils.py | 4 ++ 7 files changed, 108 insertions(+), 63 deletions(-) diff --git a/aios/hooks/syscall.py b/aios/hooks/syscall.py index feed15d7f..fd1985efc 100755 --- a/aios/hooks/syscall.py +++ b/aios/hooks/syscall.py @@ -103,29 +103,33 @@ class StorageSyscall(Syscall): class ToolSyscall(Syscall): - pass + def __init__(self, agent_name, query): + super().__init__(agent_name, query) + self.tool_calls = query def send_request(agent_name, query): action_type = query.action_type if action_type == "chat": - return llm_syscall(agent_name, query) + return llm_syscall_exec(agent_name, query) elif action_type == "tool_use": - return tool_syscall(llm_syscall(agent_name, query)) + response = llm_syscall_exec(agent_name, query)["response"] + tool_calls = response.tool_calls + return tool_syscall_exec(agent_name, tool_calls) elif action_type == "operate_file": - return storage_syscall(llm_syscall(agent_name, query)) + return storage_syscall_exec(llm_syscall_exec(agent_name, query)) elif action_type == "memory_use": return mem_syscall(agent_name, query) elif action_type == "storage_use": - return storage_syscall(agent_name, query) + return storage_syscall_exec(agent_name, query) -def storage_syscall(agent_name, query): +def storage_syscall_exec(agent_name, query): syscall = StorageSyscall(agent_name, query) syscall.set_status("active") @@ -213,8 +217,8 @@ def mem_syscall(agent_name, query): } -def tool_syscall(agent_name, query): - syscall = ToolSyscall(agent_name, query) +def tool_syscall_exec(agent_name, tool_calls): + syscall = ToolSyscall(agent_name, tool_calls) syscall.set_status("active") completed_response, start_times, end_times, waiting_times, turnaround_times = ( @@ -257,7 +261,7 @@ def tool_syscall(agent_name, query): } -def llm_syscall(agent_name, query): +def llm_syscall_exec(agent_name, query): syscall = LLMSyscall(agent_name=agent_name, query=query) syscall.set_status("active") diff --git a/aios/llm_core/llm_classes/gemini_llm.py b/aios/llm_core/llm_classes/gemini_llm.py index 6669ea11b..f6847f8ff 100644 --- a/aios/llm_core/llm_classes/gemini_llm.py +++ b/aios/llm_core/llm_classes/gemini_llm.py @@ -120,5 +120,4 @@ def process(self, # agent_request.set_status("done") # agent_request.set_end_time(time.time()) # return - print(response) return response diff --git a/aios/scheduler/fifo_scheduler.py b/aios/scheduler/fifo_scheduler.py index 1947ef36e..8b00193e0 100644 --- a/aios/scheduler/fifo_scheduler.py +++ b/aios/scheduler/fifo_scheduler.py @@ -83,10 +83,10 @@ def run_llm_request(self): agent_request.set_status("done") agent_request.set_end_time(time.time()) - self.logger.log( - f"Current request of {agent_request.agent_name} is done. Thread ID is {agent_request.get_pid()}\n", - "done", - ) + # self.logger.log( + # f"Current request of {agent_request.agent_name} is done. Thread ID is {agent_request.get_pid()}\n", + # "done", + # ) # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty except Empty: @@ -116,10 +116,10 @@ def run_memory_request(self): agent_request.set_status("done") agent_request.set_end_time(time.time()) - self.logger.log( - f"Current request of {agent_request.agent_name} is done. Thread ID is {agent_request.get_pid()}\n", - "done", - ) + # self.logger.log( + # f"Current request of {agent_request.agent_name} is done. Thread ID is {agent_request.get_pid()}\n", + # "done", + # ) # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty except Empty: @@ -132,7 +132,7 @@ def run_storage_request(self): while self.active: try: # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty - agent_request = self.get_memory_request() + agent_request = self.get_storage_request() agent_request.set_status("executing") self.logger.log( @@ -165,12 +165,12 @@ def run_tool_request(self): while self.active: try: # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty - agent_request = self.get_memory_request() + agent_request = self.get_tool_request() agent_request.set_status("executing") - self.logger.log( - f"{agent_request.agent_name} is executing. \n", "execute" - ) + # self.logger.log( + # f"{agent_request.agent_name} is executing. \n", "execute" + # ) agent_request.set_start_time(time.time()) response = self.tool_manager.address_request(agent_request) @@ -182,10 +182,10 @@ def run_tool_request(self): agent_request.set_status("done") agent_request.set_end_time(time.time()) - self.logger.log( - f"Current request of {agent_request.agent_name} is done. Thread ID is {agent_request.get_pid()}\n", - "done", - ) + # self.logger.log( + # f"Current request of {agent_request.agent_name} is done. Thread ID is {agent_request.get_pid()}\n", + # "done", + # ) # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty except Empty: diff --git a/aios/tool/manager.py b/aios/tool/manager.py index d3e1ccace..77e64ec35 100644 --- a/aios/tool/manager.py +++ b/aios/tool/manager.py @@ -1,5 +1,6 @@ import importlib - +from pyopenagi.utils.utils import snake_to_camel +from pyopenagi.utils.chat_template import Response class ToolManager: def __init__( self, @@ -9,30 +10,31 @@ def __init__( self.tool_conflict_map = {} def address_request(self, syscall) -> None: - request_data = syscall.request_data - tool_org_and_name, tool_params = ( - request_data["name"], - request_data["paramemters"], - ) - # org, tool_name = tool_org_and_name.split("/") - - if tool_org_and_name not in self.tool_conflict_map.keys(): - self.tool_conflict_map[tool_org_and_name] = 1 - tool_class = self.load_tool_instance(tool_org_and_name) + tool_calls = syscall.tool_calls + for tool_call in tool_calls: + tool_org_and_name, tool_params = ( + tool_call["name"], + tool_call["parameters"], + ) + # org, tool_name = tool_org_and_name.split("/") - tool = tool_class(tool_name=tool_org_and_name) - tool.run(params=tool_params) + if tool_org_and_name not in self.tool_conflict_map.keys(): + self.tool_conflict_map[tool_org_and_name] = 1 + tool_class = self.load_tool_instance(tool_org_and_name) - self.tool_conflict_map.pop(tool_org_and_name) + tool = tool_class() + tool_result = tool.run(params=tool_params) - def snake_to_camel(self, snake_str): - components = snake_str.split("_") - return "".join(x.title() for x in components) + self.tool_conflict_map.pop(tool_org_and_name) + + return Response( + response_message=tool_result + ) def load_tool_instance(self, tool_org_and_name): org, tool_name = tool_org_and_name.split("/") module_name = ".".join(["pyopenagi", "tools", org, tool_name]) - class_name = self.snake_to_camel(tool_name) + class_name = snake_to_camel(tool_name) tool_module = importlib.import_module(module_name) tool_instance = getattr(tool_module, class_name) return tool_instance diff --git a/pyopenagi/agents/example/academic_agent/agent.py b/pyopenagi/agents/example/academic_agent/agent.py index 9f61a8f46..1cca83fa4 100644 --- a/pyopenagi/agents/example/academic_agent/agent.py +++ b/pyopenagi/agents/example/academic_agent/agent.py @@ -9,6 +9,8 @@ from pyopenagi.utils.logger import AgentLogger +from pyopenagi.utils.utils import snake_to_camel + import json @@ -43,8 +45,6 @@ def __init__(self, agent_name, task_input, log_mode: str): self.log_mode = log_mode self.logger = self.setup_logger() - self.set_created_time(time.time()) - def setup_logger(self): logger = AgentLogger(self.agent_name, self.log_mode) @@ -53,10 +53,33 @@ def setup_logger(self): def load_config(self): script_path = os.path.abspath(__file__) script_dir = os.path.dirname(script_path) - config_file = os.path.join(script_dir, self.agent_name, "config.json") + config_file = os.path.join(script_dir, "config.json") with open(config_file, "r") as f: config = json.load(f) return config + + def load_tools(self, tool_names): + if tool_names == "None": + return + + for tool_name in tool_names: + org, name = tool_name.split("/") + module_name = ".".join(["pyopenagi", "tools", org, name]) + class_name = snake_to_camel(name) + + tool_module = importlib.import_module(module_name) + tool_class = getattr(tool_module, class_name) + + self.tool_list[name] = tool_class() + tool_format = tool_class().get_tool_call_format() + self.tools.append(tool_format) + self.tool_info.append( + { + "name": tool_format["function"]["name"], + "description": tool_format["function"]["description"], + } + ) + def build_system_instruction(self): prefix = "".join(["".join(self.config["description"])]) @@ -121,17 +144,27 @@ def automatic_workflow(self): def manual_workflow(self): workflow = [ { - "action_type": "chat", + "action_type": "tool_use", "action": "Search for relevant papers", - "tool_use": ["arxiv"], + "tool_use": ["arxiv/arxiv"], }, { - "action_type": "tool_use", + "action_type": "chat", "action": "Provide responses based on the user's query", "tool_use": [], }, ] return workflow + + def pre_select_tools(self, tool_names): + pre_selected_tools = [] + for tool_name in tool_names: + for tool in self.tools: + if tool["function"]["name"] == tool_name: + pre_selected_tools.append(tool) + break + + return pre_selected_tools def run(self): self.build_system_instruction() @@ -184,20 +217,23 @@ def run(self): action_type=action_type, ), )["response"] + + self.messages.append({"role": "assistant", "content": response.response_message}) self.rounds += 1 - self.set_status("done") - self.set_end_time(time=time.time()) - + # print(final_result) + final_result = self.messages[-1]["content"] + + print(final_result) return { "agent_name": self.agent_name, "result": final_result, "rounds": self.rounds, - "agent_waiting_time": self.start_time - self.created_time, - "agent_turnaround_time": self.end_time - self.created_time, - "request_waiting_times": self.request_waiting_times, - "request_turnaround_times": self.request_turnaround_times, + # "agent_waiting_time": self.start_time - self.created_time, + # "agent_turnaround_time": self.end_time - self.created_time, + # "request_waiting_times": self.request_waiting_times, + # "request_turnaround_times": self.request_turnaround_times, } else: @@ -205,10 +241,10 @@ def run(self): "agent_name": self.agent_name, "result": "Failed to generate a valid workflow in the given times.", "rounds": self.rounds, - "agent_waiting_time": None, - "agent_turnaround_time": None, - "request_waiting_times": self.request_waiting_times, - "request_turnaround_times": self.request_turnaround_times, + # "agent_waiting_time": None, + # "agent_turnaround_time": None, + # "request_waiting_times": self.request_waiting_times, + # "request_turnaround_times": self.request_turnaround_times, } except Exception as e: diff --git a/pyopenagi/tools/arxiv/arxiv.py b/pyopenagi/tools/arxiv/arxiv.py index 258f3a58c..4d6785c12 100644 --- a/pyopenagi/tools/arxiv/arxiv.py +++ b/pyopenagi/tools/arxiv/arxiv.py @@ -101,7 +101,7 @@ def get_tool_call_format(self): tool_call_format = { "type": "function", "function": { - "name": "arxiv", + "name": "arxiv/arxiv", "description": "Query articles or topics in arxiv", "parameters": { "type": "object", diff --git a/pyopenagi/utils/utils.py b/pyopenagi/utils/utils.py index 162243c00..8bdbd1a5b 100644 --- a/pyopenagi/utils/utils.py +++ b/pyopenagi/utils/utils.py @@ -71,3 +71,7 @@ def delete_directories(root_dir, target_dirs): full_path = os.path.join(dirpath, dirname) # print(f"Deleting {full_path}...") shutil.rmtree(full_path, ignore_errors=True) + +def snake_to_camel(snake_str): + components = snake_str.split("_") + return "".join(x.title() for x in components) \ No newline at end of file From f2335ba325cf5492e6b93eaa732cf968f0de783a Mon Sep 17 00:00:00 2001 From: 2020-qqtcg Date: Fri, 8 Nov 2024 12:41:43 +0800 Subject: [PATCH 31/41] feat: standard --- aios/hooks/llm.py | 14 +++++--- experiment/benchmark/gaia/run_infer.py | 16 +++++---- .../experiment/standard/action/action_tool.py | 15 ++++---- pyopenagi/agents/experiment/standard/agent.py | 34 +++++++++++++------ .../agents/experiment/standard/config.json | 2 +- .../standard/memory/short_term_memory.py | 4 +-- .../experiment/standard/planning/planning.py | 5 +-- 7 files changed, 55 insertions(+), 35 deletions(-) diff --git a/aios/hooks/llm.py b/aios/hooks/llm.py index 90a0c2e01..41afc959b 100644 --- a/aios/hooks/llm.py +++ b/aios/hooks/llm.py @@ -139,7 +139,9 @@ def aios_starter( max_gpu_memory, eval_device, max_new_tokens, - log_mode, + scheduler_log_mode, + agent_log_mode, + llm_kernel_log_mode, use_backend ): """ @@ -151,7 +153,9 @@ def aios_starter( max_gpu_memory (str): The maximum amount of GPU memory to use. eval_device (str): The device to evaluate the LLM on. max_new_tokens (int): The maximum number of new tokens to generate. - log_mode (str): The log mode. + agent_log_mode: + llm_kernel_log_mode: + scheduler_log_mode: use_backend (str): The backend to use for running the LLM kernel. Yields: @@ -164,15 +168,15 @@ def aios_starter( max_gpu_memory=max_gpu_memory, eval_device=eval_device, max_new_tokens=max_new_tokens, - log_mode=log_mode, + log_mode=llm_kernel_log_mode, use_backend=use_backend ) # run agents concurrently for maximum efficiency using a scheduler submit_agent, await_agent_execution = useFactory( - log_mode=log_mode, + log_mode=agent_log_mode, max_workers=64 ) - with fifo_scheduler(llm=llm, log_mode=log_mode, get_queue_message=None): + with fifo_scheduler(llm=llm, log_mode=scheduler_log_mode, get_queue_message=None): yield submit_agent, await_agent_execution diff --git a/experiment/benchmark/gaia/run_infer.py b/experiment/benchmark/gaia/run_infer.py index 3d74e1a92..397c48d89 100644 --- a/experiment/benchmark/gaia/run_infer.py +++ b/experiment/benchmark/gaia/run_infer.py @@ -36,9 +36,9 @@ def prepare_dataset(): def run_infer(outputfile: str, workers: int, aios_args: dict): dataset = prepare_dataset() + with aios_starter(**aios_args): + with ThreadPoolExecutor(max_workers=workers) as executor: - with ThreadPoolExecutor(max_workers=workers) as executor: - with aios_starter(**aios_args): futures = [] for data in dataset: # 提交任务 @@ -47,11 +47,11 @@ def run_infer(outputfile: str, workers: int, aios_args: dict): ) break - results = [] + results = [] - # Obtain infer result - for future in tqdm(as_completed(futures)): - results.append(future.result()) + # Obtain infer result + for future in tqdm(as_completed(futures)): + results.append(future.result()) # Write result into .jsonl file with open(outputfile, "w") as file: @@ -71,7 +71,9 @@ def run_infer(outputfile: str, workers: int, aios_args: dict): "max_gpu_memory": args.max_gpu_memory, "eval_device": args.eval_device, "max_new_tokens": args.max_new_tokens, - "log_mode": "console", + "scheduler_log_mode": args.scheduler_log_mode, + "agent_log_mode": args.agent_log_mode, + "llm_kernel_log_mode": args.llm_kernel_log_mode, "use_backend": args.use_backend, } diff --git a/pyopenagi/agents/experiment/standard/action/action_tool.py b/pyopenagi/agents/experiment/standard/action/action_tool.py index fdc4a69ff..54dc5ab50 100644 --- a/pyopenagi/agents/experiment/standard/action/action_tool.py +++ b/pyopenagi/agents/experiment/standard/action/action_tool.py @@ -1,20 +1,21 @@ import importlib -from typing import List, Any, Optional +from typing import Any + from pydantic.v1 import BaseModel + from pyopenagi.agents.experiment.standard.action.action import Action from pyopenagi.agents.experiment.standard.utils.config import Config from pyopenagi.agents.experiment.standard.utils.str_utils import snake_to_camel class ActionTool(Action, BaseModel): - config: Config - tools: Optional[List] - tools_format: Optional[List] + tools = {} + tools_format = [] type: str = "TOOL" - def __int__(self, *data): - super().__init__(self, *data) + def __init__(self, **data): + super().__init__(**data) self.init_tools() def __call__(self, tool_call: dict) -> Any: @@ -30,7 +31,7 @@ def __call__(self, tool_call: dict) -> Any: except TypeError: function_response = f"Call function {function_name} failed. Parameters {function_param} is invalid." - return function_response + return function_response, tool_call["id"] def init_tools(self): self._init_tools_from_config() diff --git a/pyopenagi/agents/experiment/standard/agent.py b/pyopenagi/agents/experiment/standard/agent.py index 3b6c74f0b..0c7c82075 100644 --- a/pyopenagi/agents/experiment/standard/agent.py +++ b/pyopenagi/agents/experiment/standard/agent.py @@ -3,7 +3,7 @@ from aios.hooks.request import send_request from pyopenagi.agents.experiment.standard.action.action_tool import ActionTool from pyopenagi.agents.experiment.standard.memory.short_term_memory import ShortTermMemory -from pyopenagi.agents.experiment.standard.planning.planning import Planning, DefaultPlanning +from pyopenagi.agents.experiment.standard.planning.planning import Planning, DefaultPlanning, PlanningResult from pyopenagi.agents.experiment.standard.prompt.framework_prompt import STANDARD_PROMPT from pyopenagi.agents.experiment.standard.utils.config import load_config from pyopenagi.utils.chat_template import Query, Response @@ -55,6 +55,7 @@ def custom_prompt(self) -> str: pass def _init_framework_prompt(self): + self.init_module() # Action action_prompt = self._action_prompt() planning_prompt = self._planning_prompt() @@ -62,14 +63,16 @@ def _init_framework_prompt(self): framework_prompt = STANDARD_PROMPT.format( action=action_prompt, planning=planning_prompt, + memory="", + communication="" ) self.short_term_memory.remember(role="system", content=framework_prompt) def _action_prompt(self) -> str: action_prompt = "" - for action in self.actions: - if action.disply: + for action in self.actions.values(): + if action.display: name = action.format_prompt()["name"] description = action.format_prompt()["description"] action_prompt += f"- {name}: {description}\n" @@ -85,10 +88,11 @@ def _planning_prompt(self) -> str: return planning_prompt def init_module(self): - return + self.init_planning() + self.init_actions() - def init_planning(self, planning): - self.planning = planning + def init_planning(self): + self.planning = DefaultPlanning(self.request) def init_communication(self, communication): return @@ -96,11 +100,11 @@ def init_communication(self, communication): def init_memory(self, memory): return - def init_actions(self, actions): - action_tool = ActionTool() + def init_actions(self): + action_tool = ActionTool(config=self.config) self.actions[action_tool.type] = action_tool - def planning(self) -> dict: + def run_planning(self) -> PlanningResult: # Select suitable messages messages = self.short_term_memory.recall() @@ -113,11 +117,13 @@ def run(self): # Init system prompt and task if custom_prompt := self.custom_prompt(): self.short_term_memory.remember("system", custom_prompt) + self.log_last_message() self.short_term_memory.remember("user", self.task_input) + self.log_last_message() while not self._is_terminate(): # Run planning - planning_result = self.planning() + planning_result = self.run_planning() if action_type := planning_result.action_type: action = self.actions[action_type] action_param = planning_result.action_param @@ -127,8 +133,10 @@ def run(self): response = planning_result.text_content self.short_term_memory.remember("assistant", response) + self.log_last_message() + def _is_terminate(self): - return True if "TERMINATE" in self.short_term_memory.last_message else False + return True if "TERMINATE" in self.short_term_memory.last_message()["content"] else False def request(self, messages: List, tools: List) -> Response: ( @@ -155,3 +163,7 @@ def request(self, messages: List, tools: List) -> Response: self.rounds += 1 return response + + def log_last_message(self): + log_content = self.short_term_memory.last_message()["content"] + self.logger.log(f"\n{log_content}", "info") diff --git a/pyopenagi/agents/experiment/standard/config.json b/pyopenagi/agents/experiment/standard/config.json index 6f4aba03a..1e0f6bfe1 100644 --- a/pyopenagi/agents/experiment/standard/config.json +++ b/pyopenagi/agents/experiment/standard/config.json @@ -4,7 +4,7 @@ ], "tools": [ - + "arxiv/arxiv" ], "meta": { "author": "example", diff --git a/pyopenagi/agents/experiment/standard/memory/short_term_memory.py b/pyopenagi/agents/experiment/standard/memory/short_term_memory.py index db4be8ac8..820f86001 100644 --- a/pyopenagi/agents/experiment/standard/memory/short_term_memory.py +++ b/pyopenagi/agents/experiment/standard/memory/short_term_memory.py @@ -8,10 +8,10 @@ class ShortTermMemory(BaseModel): def remember(self, role: str, content: str, tool_call_id: int = None) -> None: if tool_call_id: message = {"role": role, "content": content, "tool_call_id": tool_call_id} - self.messages += message + self.messages.append(message) else: message = {"role": role, "content": content} - self.messages += message + self.messages.append(message) def recall(self): return self.messages diff --git a/pyopenagi/agents/experiment/standard/planning/planning.py b/pyopenagi/agents/experiment/standard/planning/planning.py index c1fad557f..ebbf7faaa 100644 --- a/pyopenagi/agents/experiment/standard/planning/planning.py +++ b/pyopenagi/agents/experiment/standard/planning/planning.py @@ -30,7 +30,6 @@ def __init__(self, request_func: Callable[[List, List], Response]): def __call__(self, messages: List, tools: List): response = self.request_func(messages, tools) - response_message = response.response_message tool_calls = response.tool_calls @@ -38,7 +37,9 @@ def __call__(self, messages: List, tools: List): result.text_content = response_message if tool_calls: result.action_type = "TOOL" - result.action_param = tool_calls[0] + result.action_param = { + "tool_call": tool_calls[0] + } return result From 7a8c9d9bdcfdfd89bde05613b84f267079199b84 Mon Sep 17 00:00:00 2001 From: 2020-qqtcg Date: Fri, 8 Nov 2024 13:35:06 +0800 Subject: [PATCH 32/41] feat: standard --- experiment/benchmark/gaia.py | 0 experiment/benchmark/gaia/run_infer.py | 12 ++++++++++++ 2 files changed, 12 insertions(+) delete mode 100644 experiment/benchmark/gaia.py diff --git a/experiment/benchmark/gaia.py b/experiment/benchmark/gaia.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/experiment/benchmark/gaia/run_infer.py b/experiment/benchmark/gaia/run_infer.py index 397c48d89..06747c3ce 100644 --- a/experiment/benchmark/gaia/run_infer.py +++ b/experiment/benchmark/gaia/run_infer.py @@ -15,9 +15,21 @@ "validation" ) +SYSTEM_PROMPT = """You are a general AI assistant. I will ask you a question. Report your thoughts, and finish +your answer with the following template: FINAL ANSWER: [YOUR FINAL ANSWER]. +YOUR FINAL ANSWER should be a number OR as few words as possible OR a comma separated list of +numbers and/or strings. +If you are asked for a number, don’t use comma to write your number neither use units such as $ or percent +sign unless specified otherwise. +If you are asked for a string, don’t use articles, neither abbreviations (e.g. for cities), and write the digits in +plain text unless specified otherwise. +If you are asked for a comma separated list, apply the above rules depending of whether the element to be put +in the list is a number or a string.""" + def process_one_func(data): agent = StandardAgent("Standard Agent", data["Question"]) + agent.custom_prompt = lambda: SYSTEM_PROMPT result = agent.run() print(result) return { From 26ce6830cfb487d708f1386e8601c96023bbae7d Mon Sep 17 00:00:00 2001 From: 2020-qqtcg Date: Wed, 13 Nov 2024 01:12:49 +0800 Subject: [PATCH 33/41] feat: add file reader --- .../experiment/standard/action/action.py | 6 + pyopenagi/agents/experiment/standard/agent.py | 28 +-- .../standard/communication/communication.py | 10 + .../experiment/standard/memory/aios_memory.py | 19 ++ .../experiment/standard/memory/memory.py | 26 +- .../standard/planning/planning_augmented.py | 10 + pyopenagi/tools/reader/file_reader.py | 238 ++++++++++++++++++ requirements.txt | 5 + 8 files changed, 324 insertions(+), 18 deletions(-) create mode 100644 pyopenagi/agents/experiment/standard/memory/aios_memory.py create mode 100644 pyopenagi/agents/experiment/standard/planning/planning_augmented.py create mode 100644 pyopenagi/tools/reader/file_reader.py diff --git a/pyopenagi/agents/experiment/standard/action/action.py b/pyopenagi/agents/experiment/standard/action/action.py index 56b62c265..0e41612ef 100644 --- a/pyopenagi/agents/experiment/standard/action/action.py +++ b/pyopenagi/agents/experiment/standard/action/action.py @@ -1,8 +1,14 @@ from abc import ABC, abstractmethod +from typing import Callable, List + +from pyopenagi.utils.chat_template import Response class Action(ABC): + def __init__(self, request_func: Callable[[List, List], Response]): + self._request_func = request_func + @abstractmethod def __call__(self, *args, **kwargs): pass diff --git a/pyopenagi/agents/experiment/standard/agent.py b/pyopenagi/agents/experiment/standard/agent.py index 0c7c82075..8155dcf7b 100644 --- a/pyopenagi/agents/experiment/standard/agent.py +++ b/pyopenagi/agents/experiment/standard/agent.py @@ -1,12 +1,13 @@ import time from typing import List -from aios.hooks.request import send_request + +from aios.hooks.syscall import send_request from pyopenagi.agents.experiment.standard.action.action_tool import ActionTool from pyopenagi.agents.experiment.standard.memory.short_term_memory import ShortTermMemory -from pyopenagi.agents.experiment.standard.planning.planning import Planning, DefaultPlanning, PlanningResult +from pyopenagi.agents.experiment.standard.planning.planning import Planning, DefaultPlanning from pyopenagi.agents.experiment.standard.prompt.framework_prompt import STANDARD_PROMPT from pyopenagi.agents.experiment.standard.utils.config import load_config -from pyopenagi.utils.chat_template import Query, Response +from pyopenagi.utils.chat_template import LLMQuery, Response from pyopenagi.utils.logger import AgentLogger @@ -101,17 +102,8 @@ def init_memory(self, memory): return def init_actions(self): - action_tool = ActionTool(config=self.config) - self.actions[action_tool.type] = action_tool - - def run_planning(self) -> PlanningResult: - # Select suitable messages - messages = self.short_term_memory.recall() - - planning = DefaultPlanning(self.request) - result = planning(messages, self.tools_format) - - return result + tool = ActionTool(config=self.config, request_func=self.request) + self.actions[tool.type] = tool def run(self): # Init system prompt and task @@ -123,12 +115,16 @@ def run(self): while not self._is_terminate(): # Run planning - planning_result = self.run_planning() + messages = self.short_term_memory.recall() + planning_result = self.planning(messages, self.tools_format) + if action_type := planning_result.action_type: action = self.actions[action_type] action_param = planning_result.action_param response, tool_call_id = action(**action_param) + self.short_term_memory.remember("assistant", response, tool_call_id) + else: response = planning_result.text_content self.short_term_memory.remember("assistant", response) @@ -147,7 +143,7 @@ def request(self, messages: List, tools: List) -> Response: turnaround_times ) = send_request( agent_name=self.agent_name, - query=Query( + query=LLMQuery( messages=messages, tools=tools, action_type="message_llm", diff --git a/pyopenagi/agents/experiment/standard/communication/communication.py b/pyopenagi/agents/experiment/standard/communication/communication.py index e69de29bb..f6e55bb91 100644 --- a/pyopenagi/agents/experiment/standard/communication/communication.py +++ b/pyopenagi/agents/experiment/standard/communication/communication.py @@ -0,0 +1,10 @@ +from abc import ABC + + +class Communication(ABC): + + def send(self, *args, **kwargs): + pass + + def receive(self, *args, **kwargs): + pass diff --git a/pyopenagi/agents/experiment/standard/memory/aios_memory.py b/pyopenagi/agents/experiment/standard/memory/aios_memory.py new file mode 100644 index 000000000..66fe83ce8 --- /dev/null +++ b/pyopenagi/agents/experiment/standard/memory/aios_memory.py @@ -0,0 +1,19 @@ +from pyopenagi.agents.experiment.standard.memory.memory import Memory + + +class AIOSMemory(Memory): + + def add(self, *args, **kwargs): + pass + + def query(self, *args, **kwargs): + pass + + def update(self, *args, **kwargs): + pass + + def delete(self, *args, **kwargs): + pass + + def compress(self, *args, **kwargs): + pass diff --git a/pyopenagi/agents/experiment/standard/memory/memory.py b/pyopenagi/agents/experiment/standard/memory/memory.py index 9469f855b..aa9bc23d7 100644 --- a/pyopenagi/agents/experiment/standard/memory/memory.py +++ b/pyopenagi/agents/experiment/standard/memory/memory.py @@ -1,2 +1,24 @@ -class MemoryStandard: - ... +from abc import ABC, abstractmethod + + +class Memory(ABC): + + @abstractmethod + def add(self, *args, **kwargs): + pass + + @abstractmethod + def query(self, *args, **kwargs): + pass + + @abstractmethod + def update(self, *args, **kwargs): + pass + + @abstractmethod + def delete(self, *args, **kwargs): + pass + + @abstractmethod + def compress(self, *args, **kwargs): + pass diff --git a/pyopenagi/agents/experiment/standard/planning/planning_augmented.py b/pyopenagi/agents/experiment/standard/planning/planning_augmented.py new file mode 100644 index 000000000..dfbde8911 --- /dev/null +++ b/pyopenagi/agents/experiment/standard/planning/planning_augmented.py @@ -0,0 +1,10 @@ +from pyopenagi.agents.experiment.standard.planning.planning import Planning + + +class PlanningMemoryAugmented(Planning): + + def __call__(self, *args, **kwargs): + pass + + def format_prompt(self): + pass diff --git a/pyopenagi/tools/reader/file_reader.py b/pyopenagi/tools/reader/file_reader.py new file mode 100644 index 000000000..57a60f768 --- /dev/null +++ b/pyopenagi/tools/reader/file_reader.py @@ -0,0 +1,238 @@ +import base64 +import csv +import json +import os +import zipfile +from abc import ABC, abstractmethod + +import PyPDF2 +import pandas as pd +import pptx +import docx + +from openai import OpenAI + +from pyopenagi.tools.base import BaseTool + + +class FileReader(BaseTool): + + def __init__(self): + super().__init__() + + def run(self, param) -> str: + # query = param["query"] # Temporarily unused + path = param["path"] + + reader = get_reader(path) + content = reader.read(path) + return content + + def get_tool_call_format(self): + tool_call_format = { + "type": "function", + "function": { + "name": "reader/file_reader", + "description": "Read the file content from the specified path.", + "parameters": { + "type": "object", + "properties": { + "query": { + "type": "string", + "description": "Relevant infromation want to retrival. If want to extract all file " + "content, don't pass `query`." + }, + "path": { + "type": "string", + "description": "Input file path." + } + }, + "required": [ + "path" + ] + } + } + } + return tool_call_format + + +READER_REGISTER = {} + + +def register_reader(*args): + def decorator(cls): + for suffix in args: + READER_REGISTER[suffix] = cls + return cls + + return decorator + + +class Reader(ABC): + + @abstractmethod + def read(self, path: str) -> str: + pass + + +def get_reader(path: str) -> Reader: + filename, file_extension = os.path.splitext(path) + reader = READER_REGISTER.get(file_extension) + return reader + + +@register_reader(".jpg", ".png") +class ImageReader(Reader): + + def __init__(self): + self.client = OpenAI() + + def read(self, path: str) -> str: + with open(path, "rb") as image_file: + base64_img = base64.b64encode(image_file.read()).decode("utf-8") + + response = self.client.chat.completions.create( + model="gpt-4-vision-preview", + messages=[ + { + "role": "user", + "content": [ + {"type": "text", "text": "What's in this Image?"}, + { + "type": "image_url", + "image_url": { + "url": f"data:image/jpeg;base64,{base64_img}", + }, + }, + ], + } + ], + max_tokens=300, + ) + return response.choices[0].message.content + + +@register_reader(".pdf") +class PDFReader(Reader): + + def read(self, path: str) -> str: + content = "" + pdf = PyPDF2.PdfReader(path) + for index, page in enumerate(pdf.pages): + content += f"Page {index + 1}:\n" + page.extract_text() + return content + + +@register_reader(".pptx") +class PPTReader(Reader): + + def read(self, path: str) -> str: + content = "" + ppt = pptx.Presentation(path) + for index, slide in enumerate(ppt.slides): + content += f"Slide {index + 1}:\n" + for shape in slide.shapes: + if hasattr(shape, "text"): + content += shape.text + return content + + +@register_reader(".txt") +class TextReader(Reader): + + def read(self, path: str) -> str: + content = "" + with open(path, "r", encoding="utf-8") as file: + content += file.read() + return content + + +@register_reader(".mp3") +class AudioReader(Reader): + + def __init__(self): + self.client = OpenAI() + + def read(self, path: str) -> str: + content = "" + with open(path, "rb") as audio_file: + response = self.client.audio.transcriptions.create( + model="whisper-1", + file=audio_file + ) + content += response.texts + + return content + + +@register_reader(".xlsx") +class ExcelReader(Reader): + + def read(self, path: str) -> str: + content = "" + data = pd.read_excel(path) + content += data + return content + + +@register_reader(".json", "jsonl") +class JsonReader(Reader): + + def read(self, path): + content = "" + with open(path, "r", encoding="utf-8") as file: + if path.endswith(".json"): + content += str(json.load(file)) + elif path.endswith(".jsonl"): + content += str([json.loads(line) for line in file]) + return content + + +@register_reader(".docx") +class DocxReader(Reader): + + def read(self, path: str) -> str: + content = "" + doc = docx.Document(path) + for index, page in enumerate(doc.paragraphs): + content += f"Page {index + 1}:\n" + page.text + "\n" + return content + + +@register_reader(".py") +class PythonReader(Reader): + + def read(self, path: str) -> str: + content = "" + with open(path, "r", encoding="utf-8") as file: + content += file.read() + return content + + +@register_reader(".zip") +class ZipReader(Reader): + + def read(self, path: str) -> str: + content = "" + with zipfile.ZipFile(path, "r") as zip_file: + extract_dir = path[:-4] + '/' + zip_file.extractall(extract_dir) + for file_name in zip_file.namelist(): + content += f"File {file_name}:\n" + + sub_reader = get_reader(extract_dir + file_name) + content += sub_reader.read(extract_dir + file_name) + "\n" + + return content + + +@register_reader(".csv") +class CSVReader(Reader): + + def read(self, path: str) -> str: + content = "" + with open(path, newline='', encoding="utf-8") as file: + reader = csv.reader(file) + data = [row for row in reader] + content += str(data) + return content diff --git a/requirements.txt b/requirements.txt index 60cc30995..146140d46 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,3 +18,8 @@ pyfzf getch npm platformdirs + +# tool +PyPDF2 +python-pptx +python-docx From e26b912892a29bf8f7c98597416cf81c3cde4dba Mon Sep 17 00:00:00 2001 From: 2020-qqtcg Date: Wed, 13 Nov 2024 01:27:47 +0800 Subject: [PATCH 34/41] feat: add file reader --- .../agents/experiment/standard/config.json | 3 ++- pyopenagi/tools/reader/file_reader.py | 18 +++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/pyopenagi/agents/experiment/standard/config.json b/pyopenagi/agents/experiment/standard/config.json index 1e0f6bfe1..7b3fc3446 100644 --- a/pyopenagi/agents/experiment/standard/config.json +++ b/pyopenagi/agents/experiment/standard/config.json @@ -4,7 +4,8 @@ ], "tools": [ - "arxiv/arxiv" + "arxiv/arxiv", + "reader/file_reader" ], "meta": { "author": "example", diff --git a/pyopenagi/tools/reader/file_reader.py b/pyopenagi/tools/reader/file_reader.py index 57a60f768..529981146 100644 --- a/pyopenagi/tools/reader/file_reader.py +++ b/pyopenagi/tools/reader/file_reader.py @@ -78,7 +78,7 @@ def read(self, path: str) -> str: def get_reader(path: str) -> Reader: filename, file_extension = os.path.splitext(path) reader = READER_REGISTER.get(file_extension) - return reader + return reader() @register_reader(".jpg", ".png") @@ -92,7 +92,7 @@ def read(self, path: str) -> str: base64_img = base64.b64encode(image_file.read()).decode("utf-8") response = self.client.chat.completions.create( - model="gpt-4-vision-preview", + model="gpt-4o-mini", messages=[ { "role": "user", @@ -160,7 +160,7 @@ def read(self, path: str) -> str: model="whisper-1", file=audio_file ) - content += response.texts + content += response.text return content @@ -236,3 +236,15 @@ def read(self, path: str) -> str: data = [row for row in reader] content += str(data) return content + + +if __name__ == "__main__": + param = { + "path": "" + } + reader = FileReader() + content = reader.run(param) + print(f"File Path: {param['path']}\n" + f"\n " + f"{content}\n " + f"") From ea2c309141fef67e52ebd701ba67877b42846c59 Mon Sep 17 00:00:00 2001 From: 2020-qqtcg Date: Wed, 13 Nov 2024 01:39:47 +0800 Subject: [PATCH 35/41] feat: gaia experiment --- experiment/benchmark/gaia/run_infer.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/experiment/benchmark/gaia/run_infer.py b/experiment/benchmark/gaia/run_infer.py index 06747c3ce..c43a9d974 100644 --- a/experiment/benchmark/gaia/run_infer.py +++ b/experiment/benchmark/gaia/run_infer.py @@ -6,6 +6,7 @@ from aios.hooks.llm import aios_starter from aios.utils.utils import parse_global_args +from experiment.benchmark.gaia.init_data import REPO_PATH from pyopenagi.agents.experiment.standard.agent import StandardAgent DATA_PATH = os.path.join( @@ -24,11 +25,23 @@ If you are asked for a string, don’t use articles, neither abbreviations (e.g. for cities), and write the digits in plain text unless specified otherwise. If you are asked for a comma separated list, apply the above rules depending of whether the element to be put -in the list is a number or a string.""" +in the list is a number or a string. +""" + +FILE_PROMPT = """The current task is related to a file, and you may need to read the content of the file first. +The file path is {path}. +""" + +FILE_FOLDER = os.path.join(REPO_PATH, "2023", "validation") def process_one_func(data): - agent = StandardAgent("Standard Agent", data["Question"]) + question = data["Question"] + if data["file_name"]: + file_path = FILE_FOLDER + "/" + data["file_name"] + absolute_path = os.path.abspath(file_path) + question += ("\n" + FILE_PROMPT.format(path=absolute_path)) + agent = StandardAgent("Standard Agent", question) agent.custom_prompt = lambda: SYSTEM_PROMPT result = agent.run() print(result) From 0489e1185df186ef8a59e53736a830c138e672dc Mon Sep 17 00:00:00 2001 From: 2020-qqtcg Date: Wed, 13 Nov 2024 11:44:11 +0800 Subject: [PATCH 36/41] feat: gaia experiment run --- aios/storage/storage_classes/db_storage.py | 10 +-- experiment/benchmark/gaia/run_infer.py | 65 +++++++++++++++---- .../experiment/standard/action/action.py | 6 -- .../experiment/standard/action/action_tool.py | 16 ++--- pyopenagi/agents/experiment/standard/agent.py | 35 +++++----- .../experiment/standard/planning/planning.py | 6 +- .../standard/prompt/framework_prompt.py | 2 - pyopenagi/tools/arxiv/arxiv.py | 2 +- pyopenagi/tools/reader/file_reader.py | 4 +- 9 files changed, 88 insertions(+), 58 deletions(-) diff --git a/aios/storage/storage_classes/db_storage.py b/aios/storage/storage_classes/db_storage.py index 5c7166642..a534514d3 100644 --- a/aios/storage/storage_classes/db_storage.py +++ b/aios/storage/storage_classes/db_storage.py @@ -1,14 +1,8 @@ -from chromadb.config import Settings -from watchdog.observers import Observer -from watchdog.events import FileSystemEventHandler - import os import chromadb +from llama_index.core import SimpleDirectoryReader -from llama_index.embeddings.huggingface import HuggingFaceEmbedding - -from llama_index.core import VectorStoreIndex, SimpleDirectoryReader class ChromaDB: def __init__(self, mount_dir) -> None: @@ -79,4 +73,4 @@ def delete_file_from_collection(self, client, collection_name, file_path): def retrieve(self, name, k, keywords): results = self.collection.query(query_texts=[keywords], n_results=int(k)) print([doc[:500] for doc in results["documents"][0]]) - print(results["metadatas"]) \ No newline at end of file + print(results["metadatas"]) diff --git a/experiment/benchmark/gaia/run_infer.py b/experiment/benchmark/gaia/run_infer.py index c43a9d974..17c6eee34 100644 --- a/experiment/benchmark/gaia/run_infer.py +++ b/experiment/benchmark/gaia/run_infer.py @@ -1,10 +1,11 @@ import json import os +import re from concurrent.futures import ThreadPoolExecutor, as_completed from tqdm import tqdm -from aios.hooks.llm import aios_starter +from aios.hooks.starter import aios_starter from aios.utils.utils import parse_global_args from experiment.benchmark.gaia.init_data import REPO_PATH from pyopenagi.agents.experiment.standard.agent import StandardAgent @@ -35,27 +36,50 @@ FILE_FOLDER = os.path.join(REPO_PATH, "2023", "validation") +class GaiaExpAgent(StandardAgent): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def custom_terminate(self) -> bool: + return True if "FINAL ANSWER" in self.short_term_memory.last_message()["content"] else False + + def custom_prompt(self) -> str: + return SYSTEM_PROMPT + + def process_one_func(data): question = data["Question"] if data["file_name"]: file_path = FILE_FOLDER + "/" + data["file_name"] absolute_path = os.path.abspath(file_path) question += ("\n" + FILE_PROMPT.format(path=absolute_path)) - agent = StandardAgent("Standard Agent", question) - agent.custom_prompt = lambda: SYSTEM_PROMPT + + agent = GaiaExpAgent("Standard Agent", question) result = agent.run() - print(result) + print(f"Agent result is: {result}") + + match = re.search(r"FINAL ANSWER:\s*(.*)", result["result"]) + # Extract the content if a match is found + if match: + final_answer = match.group(1) + else: + final_answer = result["result"] return { "task_id": 1, - "result": data["Question"] + "result": final_answer } -def prepare_dataset(): +def prepare_dataset(task_id: str = None): input_file = os.path.join(DATA_PATH, "metadata.jsonl") with open(input_file, "r") as file: dataset = [json.loads(line) for line in file] + if task_id is not None: + for data in dataset: + if data["task_id"] == task_id: + return data return dataset @@ -85,10 +109,22 @@ def run_infer(outputfile: str, workers: int, aios_args: dict): file.write(json_line + "\n") +def run_infer_specify_task(outputfile: str, task_id: str, aios_args: dict): + data = prepare_dataset(task_id=task_id) + with aios_starter(**aios_args): + result = process_one_func(data) + + # Write result into .jsonl file + with open(outputfile, "w") as file: + json_line = json.dumps(result) + file.write(json_line + "\n") + + if __name__ == '__main__': parser = parse_global_args() parser.add_argument("--output_file", type=str, default="./experiment/benchmark/gaia/predictions.jsonl") parser.add_argument("--workers", type=int, default=1) + parser.add_argument("--task_id", type=str, default=None) args = parser.parse_args() aios_args = { @@ -102,8 +138,15 @@ def run_infer(outputfile: str, workers: int, aios_args: dict): "use_backend": args.use_backend, } - run_infer( - args.output_file, - args.workers, - aios_args - ) + if args.task_id is not None: + run_infer_specify_task( + args.output_file, + args.task_id, + aios_args + ) + else: + run_infer( + args.output_file, + args.workers, + aios_args + ) diff --git a/pyopenagi/agents/experiment/standard/action/action.py b/pyopenagi/agents/experiment/standard/action/action.py index 0e41612ef..56b62c265 100644 --- a/pyopenagi/agents/experiment/standard/action/action.py +++ b/pyopenagi/agents/experiment/standard/action/action.py @@ -1,14 +1,8 @@ from abc import ABC, abstractmethod -from typing import Callable, List - -from pyopenagi.utils.chat_template import Response class Action(ABC): - def __init__(self, request_func: Callable[[List, List], Response]): - self._request_func = request_func - @abstractmethod def __call__(self, *args, **kwargs): pass diff --git a/pyopenagi/agents/experiment/standard/action/action_tool.py b/pyopenagi/agents/experiment/standard/action/action_tool.py index 54dc5ab50..9f5edf1b7 100644 --- a/pyopenagi/agents/experiment/standard/action/action_tool.py +++ b/pyopenagi/agents/experiment/standard/action/action_tool.py @@ -1,21 +1,19 @@ import importlib from typing import Any -from pydantic.v1 import BaseModel - from pyopenagi.agents.experiment.standard.action.action import Action from pyopenagi.agents.experiment.standard.utils.config import Config from pyopenagi.agents.experiment.standard.utils.str_utils import snake_to_camel -class ActionTool(Action, BaseModel): - config: Config - tools = {} - tools_format = [] - type: str = "TOOL" +class ActionTool(Action): - def __init__(self, **data): - super().__init__(**data) + def __init__(self, config: Config): + super().__init__() + self.tools = {} + self.tools_format = [] + self.type = "TOOL" + self.config = config self.init_tools() def __call__(self, tool_call: dict) -> Any: diff --git a/pyopenagi/agents/experiment/standard/agent.py b/pyopenagi/agents/experiment/standard/agent.py index 8155dcf7b..ac3f343c1 100644 --- a/pyopenagi/agents/experiment/standard/agent.py +++ b/pyopenagi/agents/experiment/standard/agent.py @@ -1,6 +1,5 @@ import time from typing import List - from aios.hooks.syscall import send_request from pyopenagi.agents.experiment.standard.action.action_tool import ActionTool from pyopenagi.agents.experiment.standard.memory.short_term_memory import ShortTermMemory @@ -52,6 +51,12 @@ def tools_format(self): else: return None + def _is_terminate(self): + return self.custom_terminate() + + def custom_terminate(self) -> bool: + pass + def custom_prompt(self) -> str: pass @@ -102,7 +107,7 @@ def init_memory(self, memory): return def init_actions(self): - tool = ActionTool(config=self.config, request_func=self.request) + tool = ActionTool(config=self.config) self.actions[tool.type] = tool def run(self): @@ -131,35 +136,31 @@ def run(self): self.log_last_message() - def _is_terminate(self): - return True if "TERMINATE" in self.short_term_memory.last_message()["content"] else False + return { + "agent_name": self.agent_name, + "result": self.short_term_memory.last_message()["content"], + "rounds": self.rounds, + } def request(self, messages: List, tools: List) -> Response: - ( - response, - start_times, - end_times, - waiting_times, - turnaround_times - ) = send_request( + response = send_request( agent_name=self.agent_name, query=LLMQuery( messages=messages, tools=tools, - action_type="message_llm", ) ) # Update AIOS monitor info if self.rounds == 0: - self.start_time = start_times[0] + self.start_time = response["start_times"][0] - self.request_waiting_times.extend(waiting_times) - self.request_turnaround_times.extend(turnaround_times) + self.request_waiting_times.extend(response["waiting_times"]) + self.request_turnaround_times.extend(response["turnaround_times"]) self.rounds += 1 - return response + return response["response"] def log_last_message(self): log_content = self.short_term_memory.last_message()["content"] - self.logger.log(f"\n{log_content}", "info") + self.logger.log(f"\n{log_content}\n", "info") diff --git a/pyopenagi/agents/experiment/standard/planning/planning.py b/pyopenagi/agents/experiment/standard/planning/planning.py index ebbf7faaa..0896bddf2 100644 --- a/pyopenagi/agents/experiment/standard/planning/planning.py +++ b/pyopenagi/agents/experiment/standard/planning/planning.py @@ -30,8 +30,10 @@ def __init__(self, request_func: Callable[[List, List], Response]): def __call__(self, messages: List, tools: List): response = self.request_func(messages, tools) - response_message = response.response_message - tool_calls = response.tool_calls + if tool_calls := response.tool_calls: + response_message = None + else: + response_message = response.response_message result = PlanningResult() result.text_content = response_message diff --git a/pyopenagi/agents/experiment/standard/prompt/framework_prompt.py b/pyopenagi/agents/experiment/standard/prompt/framework_prompt.py index 2bebebf41..5c0a77552 100644 --- a/pyopenagi/agents/experiment/standard/prompt/framework_prompt.py +++ b/pyopenagi/agents/experiment/standard/prompt/framework_prompt.py @@ -26,6 +26,4 @@ {communication} - -If you think the task is done, reply TERMINATE. """ diff --git a/pyopenagi/tools/arxiv/arxiv.py b/pyopenagi/tools/arxiv/arxiv.py index 4d6785c12..258f3a58c 100644 --- a/pyopenagi/tools/arxiv/arxiv.py +++ b/pyopenagi/tools/arxiv/arxiv.py @@ -101,7 +101,7 @@ def get_tool_call_format(self): tool_call_format = { "type": "function", "function": { - "name": "arxiv/arxiv", + "name": "arxiv", "description": "Query articles or topics in arxiv", "parameters": { "type": "object", diff --git a/pyopenagi/tools/reader/file_reader.py b/pyopenagi/tools/reader/file_reader.py index 529981146..ee01ba5ba 100644 --- a/pyopenagi/tools/reader/file_reader.py +++ b/pyopenagi/tools/reader/file_reader.py @@ -32,7 +32,7 @@ def get_tool_call_format(self): tool_call_format = { "type": "function", "function": { - "name": "reader/file_reader", + "name": "file_reader", "description": "Read the file content from the specified path.", "parameters": { "type": "object", @@ -171,7 +171,7 @@ class ExcelReader(Reader): def read(self, path: str) -> str: content = "" data = pd.read_excel(path) - content += data + content += data.to_string() return content From 7abe01886294c006627261d80c47ed4642007d52 Mon Sep 17 00:00:00 2001 From: 2020-qqtcg Date: Fri, 15 Nov 2024 00:06:49 +0800 Subject: [PATCH 37/41] feat: code env --- experiment/benchmark/gaia/run_eval.py | 37 ++++++++ experiment/benchmark/gaia/run_infer.py | 31 ++++--- .../experiment/standard/action/action_code.py | 43 +++++++++ .../experiment/standard/action/action_tool.py | 2 + pyopenagi/agents/experiment/standard/agent.py | 9 ++ .../standard/environment/__init__.py | 0 .../standard/environment/code_environment.py | 34 +++++++ .../standard/environment/environment.py | 17 ++++ .../experiment/standard/planning/planning.py | 25 ++++- .../standard/planning/planning_reflexion.py | 0 pyopenagi/tools/reader/file_reader.py | 92 ++++++++++++++++++- 11 files changed, 277 insertions(+), 13 deletions(-) create mode 100644 experiment/benchmark/gaia/run_eval.py create mode 100644 pyopenagi/agents/experiment/standard/environment/__init__.py create mode 100644 pyopenagi/agents/experiment/standard/environment/code_environment.py create mode 100644 pyopenagi/agents/experiment/standard/environment/environment.py create mode 100644 pyopenagi/agents/experiment/standard/planning/planning_reflexion.py diff --git a/experiment/benchmark/gaia/run_eval.py b/experiment/benchmark/gaia/run_eval.py new file mode 100644 index 000000000..95f5e05b9 --- /dev/null +++ b/experiment/benchmark/gaia/run_eval.py @@ -0,0 +1,37 @@ +import json +from argparse import ArgumentParser +from experiment.benchmark.gaia.run_infer import prepare_dataset + + +def run_eval(input_file: str, output_file: str): + dataset = prepare_dataset() + dataset_map = {data["task_id"]: data for data in dataset} + with open(input_file, "r", encoding="utf-8") as file: + predictions = [json.loads(line) for line in file] + + pass_num = 0 + for prediction in predictions: + task_id = prediction["task_id"] + result = prediction["result"] + true_result = dataset_map[task_id]["Final answer"] + if result == true_result: + prediction["pass"] = True + pass_num += 1 + else: + prediction["pass"] = False + prediction["true_result"] = true_result + + with open(output_file, "w") as file: + for line in predictions: + json_line = json.dumps(line) + file.write(json_line + "\n") + + print(f"Gaia passed: {pass_num}, total: {len(predictions)}, pass rate: {pass_num/len(predictions)}") + + +if __name__ == '__main__': + parser = ArgumentParser() + parser.add_argument("--input_file", type=str, default="./experiment/benchmark/gaia/predictions.jsonl") + parser.add_argument("--output_file", type=str, default="./experiment/benchmark/gaia/report.jsonl") + args = parser.parse_args() + run_eval(args.input_file, args.output_file) diff --git a/experiment/benchmark/gaia/run_infer.py b/experiment/benchmark/gaia/run_infer.py index 17c6eee34..b170cdc05 100644 --- a/experiment/benchmark/gaia/run_infer.py +++ b/experiment/benchmark/gaia/run_infer.py @@ -42,6 +42,8 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def custom_terminate(self) -> bool: + if self.rounds > 10: + return True return True if "FINAL ANSWER" in self.short_term_memory.last_message()["content"] else False def custom_prompt(self) -> str: @@ -57,7 +59,6 @@ def process_one_func(data): agent = GaiaExpAgent("Standard Agent", question) result = agent.run() - print(f"Agent result is: {result}") match = re.search(r"FINAL ANSWER:\s*(.*)", result["result"]) # Extract the content if a match is found @@ -65,10 +66,14 @@ def process_one_func(data): final_answer = match.group(1) else: final_answer = result["result"] - return { - "task_id": 1, + + prediction = { + "task_id": data["task_id"], + "level": data["Level"], "result": final_answer } + print(f"Finished Task: \n{prediction}") + return prediction def prepare_dataset(task_id: str = None): @@ -83,24 +88,26 @@ def prepare_dataset(task_id: str = None): return dataset -def run_infer(outputfile: str, workers: int, aios_args: dict): +def run_infer(outputfile: str, workers: int, level: int, aios_args: dict): dataset = prepare_dataset() with aios_starter(**aios_args): with ThreadPoolExecutor(max_workers=workers) as executor: futures = [] for data in dataset: - # 提交任务 + # submit task + if level and data["Level"] != level: + continue + futures.append( executor.submit(process_one_func, data) ) - break - results = [] + results = [] - # Obtain infer result - for future in tqdm(as_completed(futures)): - results.append(future.result()) + # Obtain infer result + for future in tqdm(as_completed(futures), total=len(futures), desc="Finished"): + results.append(future.result()) # Write result into .jsonl file with open(outputfile, "w") as file: @@ -115,7 +122,7 @@ def run_infer_specify_task(outputfile: str, task_id: str, aios_args: dict): result = process_one_func(data) # Write result into .jsonl file - with open(outputfile, "w") as file: + with open(outputfile, "w", encoding="utf-8") as file: json_line = json.dumps(result) file.write(json_line + "\n") @@ -125,6 +132,7 @@ def run_infer_specify_task(outputfile: str, task_id: str, aios_args: dict): parser.add_argument("--output_file", type=str, default="./experiment/benchmark/gaia/predictions.jsonl") parser.add_argument("--workers", type=int, default=1) parser.add_argument("--task_id", type=str, default=None) + parser.add_argument("--level", type=int, default=None) args = parser.parse_args() aios_args = { @@ -148,5 +156,6 @@ def run_infer_specify_task(outputfile: str, task_id: str, aios_args: dict): run_infer( args.output_file, args.workers, + args.level, aios_args ) diff --git a/pyopenagi/agents/experiment/standard/action/action_code.py b/pyopenagi/agents/experiment/standard/action/action_code.py index e69de29bb..245af4194 100644 --- a/pyopenagi/agents/experiment/standard/action/action_code.py +++ b/pyopenagi/agents/experiment/standard/action/action_code.py @@ -0,0 +1,43 @@ +from pyopenagi.agents.experiment.standard.action.action import Action +from pyopenagi.agents.experiment.standard.environment.code_environment import CodeEnvironment + +CODE_PROMPT = """You can write code to solve problem. If you want to write code to solve problem, surrounding your +code with a code block. A code block should like: + +```python +def main(): + print("hello") + +if __name__ == '__main__': + main() +``` + +If additional dependencies are required, please provid the command install them, format like: + +```requirement +pip install torch +pip install numpy +``` +""" + + +class ActionCode(Action): + + def __init__(self, environment: CodeEnvironment): + super().__init__() + self.type = "CODE" + self.environment = environment + + def __call__(self, code: str, requirements: str): + return self.execute_code(code, requirements) + + def execute_code(self, code: str, requirements: str): + self.environment.init_environment(requirements) + exec_res = self.environment.step(code) + return exec_res + + def format_prompt(self): + return { + "name": "code", + "description": CODE_PROMPT + } diff --git a/pyopenagi/agents/experiment/standard/action/action_tool.py b/pyopenagi/agents/experiment/standard/action/action_tool.py index 9f5edf1b7..ff44f5234 100644 --- a/pyopenagi/agents/experiment/standard/action/action_tool.py +++ b/pyopenagi/agents/experiment/standard/action/action_tool.py @@ -28,6 +28,8 @@ def __call__(self, tool_call: dict) -> Any: except TypeError: function_response = f"Call function {function_name} failed. Parameters {function_param} is invalid." + except Exception as e: + function_response = f"Tool error is {e}" return function_response, tool_call["id"] diff --git a/pyopenagi/agents/experiment/standard/agent.py b/pyopenagi/agents/experiment/standard/agent.py index ac3f343c1..f3093388b 100644 --- a/pyopenagi/agents/experiment/standard/agent.py +++ b/pyopenagi/agents/experiment/standard/agent.py @@ -1,7 +1,9 @@ import time from typing import List from aios.hooks.syscall import send_request +from pyopenagi.agents.experiment.standard.action.action_code import ActionCode from pyopenagi.agents.experiment.standard.action.action_tool import ActionTool +from pyopenagi.agents.experiment.standard.environment.code_environment import LocalCodeEnvironment from pyopenagi.agents.experiment.standard.memory.short_term_memory import ShortTermMemory from pyopenagi.agents.experiment.standard.planning.planning import Planning, DefaultPlanning from pyopenagi.agents.experiment.standard.prompt.framework_prompt import STANDARD_PROMPT @@ -107,8 +109,15 @@ def init_memory(self, memory): return def init_actions(self): + # Tool tool = ActionTool(config=self.config) + + # Code + environment = LocalCodeEnvironment() + code = ActionCode(environment=environment) + self.actions[tool.type] = tool + self.actions[code.type] = code def run(self): # Init system prompt and task diff --git a/pyopenagi/agents/experiment/standard/environment/__init__.py b/pyopenagi/agents/experiment/standard/environment/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyopenagi/agents/experiment/standard/environment/code_environment.py b/pyopenagi/agents/experiment/standard/environment/code_environment.py new file mode 100644 index 000000000..141b2697d --- /dev/null +++ b/pyopenagi/agents/experiment/standard/environment/code_environment.py @@ -0,0 +1,34 @@ +from abc import ABC +from typing import List + +from pyopenagi.agents.experiment.standard.environment.environment import Environment + + +class CodeEnvironment(Environment, ABC): + """ + Environment for code. + """ + + +class LocalCodeEnvironment(CodeEnvironment): + """ + Local code environment. + """ + + def init_environment(self, requirement_list: List[str]): + pass + + def step(self, code_block: str): + pass + + +class DockerCodeEnvironment(CodeEnvironment): + """ + Docker code environment. + """ + + def init_environment(self, *args, **kwargs): + pass + + def step(self, *args, **kwargs): + pass diff --git a/pyopenagi/agents/experiment/standard/environment/environment.py b/pyopenagi/agents/experiment/standard/environment/environment.py new file mode 100644 index 000000000..344d13b8c --- /dev/null +++ b/pyopenagi/agents/experiment/standard/environment/environment.py @@ -0,0 +1,17 @@ +from abc import ABC, abstractmethod + + +class Environment(ABC): + """ + Environment abstract base class. The environment is the foundation for the agent to execute actions. + """ + + @abstractmethod + def init_environment(self, *args, **kwargs): + """Init environment, prepare something required""" + pass + + @abstractmethod + def step(self, *args, **kwargs): + """Take a step in the environment""" + pass diff --git a/pyopenagi/agents/experiment/standard/planning/planning.py b/pyopenagi/agents/experiment/standard/planning/planning.py index 0896bddf2..bd9b7025e 100644 --- a/pyopenagi/agents/experiment/standard/planning/planning.py +++ b/pyopenagi/agents/experiment/standard/planning/planning.py @@ -1,3 +1,4 @@ +import re from abc import ABC, abstractmethod from typing import List, Callable, Optional, Any @@ -37,16 +38,38 @@ def __call__(self, messages: List, tools: List): result = PlanningResult() result.text_content = response_message + if tool_calls: + # action tool result.action_type = "TOOL" result.action_param = { "tool_call": tool_calls[0] } + return result + + if code_info := extract_code(response_message): + # action code + result.action_type = "CODE" + result.action_param = { + "code": code_info[0], + "requirements": code_info[1], + } + return result return result def format_prompt(self): return { "name": "normal", - "description": "Planning as normal." + "description": "Try to solve promble step by step. Think more before you try to give final answer." } + + +def extract_code(message) -> tuple[str, str] | None: + """extract code from message""" + code_match = re.search(r'```python\s*([\s\S]*?)```', message) + requirements_match = re.search(r'```requirements\s*([\s\S]*?)```', message) + + code = code_match.group(1) if code_match else None + requirements = requirements_match.group(1) if requirements_match else None + return code, requirements diff --git a/pyopenagi/agents/experiment/standard/planning/planning_reflexion.py b/pyopenagi/agents/experiment/standard/planning/planning_reflexion.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyopenagi/tools/reader/file_reader.py b/pyopenagi/tools/reader/file_reader.py index ee01ba5ba..9b0a96259 100644 --- a/pyopenagi/tools/reader/file_reader.py +++ b/pyopenagi/tools/reader/file_reader.py @@ -60,6 +60,18 @@ def get_tool_call_format(self): def register_reader(*args): + """ + A decorator to register a reader class into the READER_REGISTER dictionary. + + Usage: + @register_reader(".pdf", ".docx") + class PDFReader(Reader): + # implement the read method + pass + + In this example, the PDFReader class is registered to handle files with ".pdf" + and ".docx" extensions. + """ def decorator(cls): for suffix in args: READER_REGISTER[suffix] = cls @@ -76,6 +88,17 @@ def read(self, path: str) -> str: def get_reader(path: str) -> Reader: + """ + Retrieves a reader instance based on the file extension of the given path. + + Args: + path (str): The file path for which to get the corresponding reader. + + Returns: + Reader: An instance of a reader class that can handle the file extension + of the given path. This instance is expected to implement the `read` method + to process the file content. + """ filename, file_extension = os.path.splitext(path) reader = READER_REGISTER.get(file_extension) return reader() @@ -83,6 +106,9 @@ def get_reader(path: str) -> Reader: @register_reader(".jpg", ".png") class ImageReader(Reader): + """ + Reads image files and recognizes their content using the OpenAI API. + """ def __init__(self): self.client = OpenAI() @@ -114,6 +140,9 @@ def read(self, path: str) -> str: @register_reader(".pdf") class PDFReader(Reader): + """ + Reads PDF files and returns the content of each page as plain text. + """ def read(self, path: str) -> str: content = "" @@ -125,6 +154,14 @@ def read(self, path: str) -> str: @register_reader(".pptx") class PPTReader(Reader): + """ + Reads PowerPoint files (.pptx) and returns the content of each slide as plain text. + + The content of each slide is concatenated and returned as a single string. + + Note: This reader does not support PPT files that contain images or other + non-text content. + """ def read(self, path: str) -> str: content = "" @@ -137,8 +174,13 @@ def read(self, path: str) -> str: return content -@register_reader(".txt") +@register_reader(".txt", ".pdb") class TextReader(Reader): + """ + Reads plain text files (.txt and .pdb) and returns the content as a string. + + The content of the file is read and returned as a single string. + """ def read(self, path: str) -> str: content = "" @@ -149,6 +191,14 @@ def read(self, path: str) -> str: @register_reader(".mp3") class AudioReader(Reader): + """ + Reads audio files (.mp3) and transcribes the content using the Whisper API. + + This reader uses the Whisper API to transcribe the audio file and returns the + transcription as a string. + + Note: This reader requires an OpenAI API key to be set in the environment. + """ def __init__(self): self.client = OpenAI() @@ -167,6 +217,14 @@ def read(self, path: str) -> str: @register_reader(".xlsx") class ExcelReader(Reader): + """ + Reads Excel files (.xlsx) and returns the content as a string. + + The content of the file is read into a pandas DataFrame and then converted + to a string using the `to_string` method. + + Note: This reader requires the `pandas` library to be installed. + """ def read(self, path: str) -> str: content = "" @@ -177,6 +235,13 @@ def read(self, path: str) -> str: @register_reader(".json", "jsonl") class JsonReader(Reader): + """ + Reads JSON and JSONL files and returns their content as a string. + + For JSON files, the content is loaded as a dictionary and converted to a string. + For JSONL files, each line is loaded as a JSON object and the list of these + objects is converted to a string. + """ def read(self, path): content = "" @@ -190,6 +255,12 @@ def read(self, path): @register_reader(".docx") class DocxReader(Reader): + """ + Reads DOCX files and returns the content as plain text. + + This reader processes each paragraph in the DOCX file, appending + it to the content string with a page indicator. + """ def read(self, path: str) -> str: content = "" @@ -201,6 +272,11 @@ def read(self, path: str) -> str: @register_reader(".py") class PythonReader(Reader): + """ + Reads Python files (.py) and returns their content as a string. + + The content of the file is read and returned as a single string. + """ def read(self, path: str) -> str: content = "" @@ -211,6 +287,14 @@ def read(self, path: str) -> str: @register_reader(".zip") class ZipReader(Reader): + """ + Reads the content of a ZIP file. + + This reader will extract the ZIP file to the same directory and then + read the content of each file in the ZIP file. The content of each file + is processed by the corresponding reader and the results are concatenated + together with each file's name and content separated by a blank line. + """ def read(self, path: str) -> str: content = "" @@ -228,6 +312,12 @@ def read(self, path: str) -> str: @register_reader(".csv") class CSVReader(Reader): + """ + Reads CSV files and returns their content as a string. + + The content of the CSV file is read into a list of rows, where each row is a list of values. + The list is then converted to a string and returned. + """ def read(self, path: str) -> str: content = "" From cf960c1a96bb75c42d7f2649efa24b71e974b6f3 Mon Sep 17 00:00:00 2001 From: 2020-qqtcg Date: Fri, 15 Nov 2024 00:49:04 +0800 Subject: [PATCH 38/41] feat: code env --- .../experiment/standard/action/action_code.py | 20 +++++++- .../standard/environment/code_environment.py | 49 +++++++++++++++++-- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/pyopenagi/agents/experiment/standard/action/action_code.py b/pyopenagi/agents/experiment/standard/action/action_code.py index 245af4194..34537298e 100644 --- a/pyopenagi/agents/experiment/standard/action/action_code.py +++ b/pyopenagi/agents/experiment/standard/action/action_code.py @@ -29,10 +29,28 @@ def __init__(self, environment: CodeEnvironment): self.environment = environment def __call__(self, code: str, requirements: str): + """ + Execute code with requirements. + """ return self.execute_code(code, requirements) def execute_code(self, code: str, requirements: str): - self.environment.init_environment(requirements) + """ + Execute code with requirements. + + Args: + code (str): The code to be executed. + requirements (str): The command to install additional dependencies. + + Returns: + str: The result of the code execution. + """ + + init_err = self.environment.init_environment(requirements) + if init_err: + # If init error, return error msg + return init_err + exec_res = self.environment.step(code) return exec_res diff --git a/pyopenagi/agents/experiment/standard/environment/code_environment.py b/pyopenagi/agents/experiment/standard/environment/code_environment.py index 141b2697d..22d38c5c6 100644 --- a/pyopenagi/agents/experiment/standard/environment/code_environment.py +++ b/pyopenagi/agents/experiment/standard/environment/code_environment.py @@ -1,3 +1,6 @@ +import subprocess +import sys +import tempfile from abc import ABC from typing import List @@ -16,10 +19,50 @@ class LocalCodeEnvironment(CodeEnvironment): """ def init_environment(self, requirement_list: List[str]): - pass + """ + Initialize the environment with requirements. - def step(self, code_block: str): - pass + Args: + requirement_list (List[str]): The list of requirement commands(Format like `pip install numpy`). + + """ + if len(requirement_list) == 0: + return + + for requirement in requirement_list: + if "pip install" in requirement: + package = requirement.split(" ")[-1] + else: + package = requirement + try: + subprocess.run([sys.executable, "-m", "pip", "install", package], check=True) + print(f"Run command successfully: `pip install {package}`") + except subprocess.CalledProcessError as e: + err_msg = (f"Run command failed: `pip install {package}`\n" + f"Return code: {e.returncode}\n" + f"Error message: {e.stderr}\n" + f"Output: {e.stdout}") + print(err_msg) + return err_msg + + def step(self, code_block: str, language: str = "python"): + # Create temp file, write python code into temp file, then execute it + with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=True) as temp_file: + temp_file.write(code_block) + try: + exec_res = subprocess.run( + ["python", temp_file.name], + capture_output=True, + text=True, + check=True) + step_res = exec_res.stdout + except subprocess.CalledProcessError as e: + err_msg = (f"Run python code failed:`\n" + f"Return code: {e.returncode}\n" + f"Error message: {e.stderr}\n" + f"Output: {e.stdout}") + step_res = err_msg + return step_res class DockerCodeEnvironment(CodeEnvironment): From 25738e8a13ddf7e9b78f4acb22d4610f767d07fa Mon Sep 17 00:00:00 2001 From: 2020-qqtcg Date: Fri, 15 Nov 2024 01:01:07 +0800 Subject: [PATCH 39/41] feat: code env --- .../experiment/standard/action/action_code.py | 3 ++ .../experiment/standard/action/action_tool.py | 31 +++++++++++++++++++ .../standard/environment/code_environment.py | 10 ++++++ .../standard/prompt/framework_prompt.py | 14 ++++----- 4 files changed, 51 insertions(+), 7 deletions(-) diff --git a/pyopenagi/agents/experiment/standard/action/action_code.py b/pyopenagi/agents/experiment/standard/action/action_code.py index 34537298e..43d4812c7 100644 --- a/pyopenagi/agents/experiment/standard/action/action_code.py +++ b/pyopenagi/agents/experiment/standard/action/action_code.py @@ -22,6 +22,9 @@ def main(): class ActionCode(Action): + """ + Action responsible for writing code to solve problem. + """ def __init__(self, environment: CodeEnvironment): super().__init__() diff --git a/pyopenagi/agents/experiment/standard/action/action_tool.py b/pyopenagi/agents/experiment/standard/action/action_tool.py index ff44f5234..7869ff3bd 100644 --- a/pyopenagi/agents/experiment/standard/action/action_tool.py +++ b/pyopenagi/agents/experiment/standard/action/action_tool.py @@ -7,6 +7,9 @@ class ActionTool(Action): + """ + Action responsible for support tool call. + """ def __init__(self, config: Config): super().__init__() @@ -17,6 +20,34 @@ def __init__(self, config: Config): self.init_tools() def __call__(self, tool_call: dict) -> Any: + """ + Execute a tool call. + """ + return self.execute(tool_call) + + def execute(self, tool_call: dict) -> Any: + """ + Execute the tool call. + + Args: + tool_call (dict): A dictionary contain function name and parameters. + Example: + { + "name": "function_name", + "parameters": { + "param1": "value1", + "param2": "value2" + } + } + + Returns: + tuple: A tuple of two elements. The first element is the response of the function call, + the second element is the tool call id. + + Raises: + TypeError: If the parameters of the function call is invalid. + Exception: If any other exception occurs. + """ if tool_call is None: return diff --git a/pyopenagi/agents/experiment/standard/environment/code_environment.py b/pyopenagi/agents/experiment/standard/environment/code_environment.py index 22d38c5c6..7a6a09620 100644 --- a/pyopenagi/agents/experiment/standard/environment/code_environment.py +++ b/pyopenagi/agents/experiment/standard/environment/code_environment.py @@ -46,6 +46,16 @@ def init_environment(self, requirement_list: List[str]): return err_msg def step(self, code_block: str, language: str = "python"): + """ + Execute the given code block in a temporary file. + + Args: + code_block (str): The code block to be executed. + language (str, optional): The language of the code block. Defaults to "python". + + Returns: + str: The result of the code execution. + """ # Create temp file, write python code into temp file, then execute it with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=True) as temp_file: temp_file.write(code_block) diff --git a/pyopenagi/agents/experiment/standard/prompt/framework_prompt.py b/pyopenagi/agents/experiment/standard/prompt/framework_prompt.py index 5c0a77552..db2eb968c 100644 --- a/pyopenagi/agents/experiment/standard/prompt/framework_prompt.py +++ b/pyopenagi/agents/experiment/standard/prompt/framework_prompt.py @@ -11,19 +11,19 @@ The following will explain the functions of the modules and how to use them. - -{action} - - -{planning} + {planning} + + {action} + + -{memory} + {memory} -{communication} + {communication} """ From 3b4848ee9d0179ba6d65aba8cfde09088f9961c7 Mon Sep 17 00:00:00 2001 From: 2020-qqtcg Date: Wed, 20 Nov 2024 00:25:18 +0800 Subject: [PATCH 40/41] feat: merge --- README.md | 2 +- agent_repl.py | 44 ++--- .../agents/ContentLayout/DatasetsHeader.tsx | 26 +-- .../app/agents/TabsLayout/index.client.tsx | 144 ++++++++------ agenthub/app/agents/const.ts | 31 ++- agenthub/app/agents/page.tsx | 19 +- agenthub/app/agents/type.ts | 6 +- agenthub/app/chat/page.tsx | 113 ++++++----- agenthub/components/agentchat/Header.tsx | 9 +- agenthub/components/agentchat/Sidebar.tsx | 78 +++++--- agenthub/components/homepage/Products.tsx | 4 +- agenthub/interfaces/agentchat.ts | 14 ++ agenthub/lib/env.ts | 9 +- agenthub/public/MentionListV2Light.scss | 14 +- aios/hooks/starter.py | 14 +- aios/hooks/syscall.py | 54 +++--- aios/hooks/types/scheduler.py | 12 +- aios/llm_core/llm_classes/base_llm.py | 65 +++---- aios/llm_core/llm_classes/gemini_llm.py | 91 ++++----- aios/llm_core/llm_classes/gpt_llm.py | 98 +++++++--- aios/llm_core/llm_classes/hf_native_llm.py | 50 ++--- aios/llm_core/llm_classes/vllm.py | 26 +-- aios/llm_core/llms.py | 12 +- aios/llm_cores/adapter.py | 80 ++++++++ aios/llm_cores/base.py | 119 ++++++++++++ aios/llm_cores/providers/api/anthropic.py | 158 +++++++++++++++ .../providers/api/bedrock.py} | 0 aios/llm_cores/providers/api/google.py | 100 ++++++++++ .../llm_cores/providers/api/groq.py | 0 aios/llm_cores/providers/api/openai.py | 98 ++++++++++ aios/llm_cores/providers/local/huggingface.py | 0 aios/llm_cores/providers/local/ollama.py | 0 aios/llm_cores/providers/local/vllm.py | 0 aios/llm_cores/registry.py | 33 ++++ aios/scheduler/base.py | 74 +++++-- aios/scheduler/fifo_scheduler.py | 181 ++++++------------ aios/scheduler/rr_scheduler.py | 105 ++++------ aios/sdk/autogen/client_adapter.py | 8 +- aios/sdk/interpreter/adapter.py | 8 +- aios/sdk/metagpt/adapter.py | 4 +- aios/tool/manager.py | 5 +- aios/utils/utils.py | 2 +- experiment/agent/autogen.py | 8 +- experiment/agent/interpreter.py | 8 +- experiment/agent/metagpt.py | 4 +- experiment/gaia/inference.py | 39 ++-- main.py | 4 +- .../agents/example/seeact_agent/agent.py | 32 ++-- .../action/{action_code.py => code.py} | 30 ++- .../action/{action_tool.py => tool.py} | 0 pyopenagi/agents/experiment/standard/agent.py | 11 +- .../standard/communication/communication.py | 4 +- .../standard/communication/message_pool.py | 24 +++ .../agents/experiment/standard/config.json | 2 - .../standard/environment/code_environment.py | 5 +- ...nning_augmented.py => memory_augmented.py} | 0 .../experiment/standard/planning/planning.py | 3 +- .../experiment/standard/planning/reflexion.py | 0 pyopenagi/utils/chat_template.py | 28 ++- .../example_aios_interpreter.py | 2 +- scripts/aios-seeact/README.md | 2 +- scripts/aios-seeact/run_seeact.py | 18 +- server.py | 20 ++ standard_main.py | 30 --- 64 files changed, 1456 insertions(+), 728 deletions(-) create mode 100644 agenthub/interfaces/agentchat.ts create mode 100644 aios/llm_cores/adapter.py create mode 100644 aios/llm_cores/base.py create mode 100644 aios/llm_cores/providers/api/anthropic.py rename aios/{hooks/types/hooks.py => llm_cores/providers/api/bedrock.py} (100%) create mode 100644 aios/llm_cores/providers/api/google.py rename pyopenagi/agents/experiment/standard/planning/planning_reflexion.py => aios/llm_cores/providers/api/groq.py (100%) create mode 100644 aios/llm_cores/providers/api/openai.py create mode 100644 aios/llm_cores/providers/local/huggingface.py create mode 100644 aios/llm_cores/providers/local/ollama.py create mode 100644 aios/llm_cores/providers/local/vllm.py create mode 100644 aios/llm_cores/registry.py rename pyopenagi/agents/experiment/standard/action/{action_code.py => code.py} (68%) rename pyopenagi/agents/experiment/standard/action/{action_tool.py => tool.py} (100%) create mode 100644 pyopenagi/agents/experiment/standard/communication/message_pool.py rename pyopenagi/agents/experiment/standard/planning/{planning_augmented.py => memory_augmented.py} (100%) create mode 100644 pyopenagi/agents/experiment/standard/planning/reflexion.py delete mode 100644 standard_main.py diff --git a/README.md b/README.md index 9242aea30..a985c00a6 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ - + [![Code License](https://img.shields.io/badge/Code%20License-MIT-orange.svg)](https://github.com/agiresearch/AIOS/blob/main/LICENSE) [![Gurubase](https://img.shields.io/badge/Gurubase-Ask%20AIOS%20Guru-006BFF)](https://gurubase.io/g/aios) diff --git a/agent_repl.py b/agent_repl.py index 061d320a7..520b918ba 100644 --- a/agent_repl.py +++ b/agent_repl.py @@ -1,18 +1,15 @@ -import argparse +import warnings from typing import List, Tuple -from fastapi import Depends +from dotenv import load_dotenv -from aios.hooks.llm import useFactory, useKernel, useFIFOScheduler -from aios.utils.utils import delete_directories, humanify_agent, parse_global_args +from aios.hooks.modules.agent import useFactory +from aios.hooks.modules.llm import useCore +from aios.hooks.modules.scheduler import useFIFOScheduler from aios.utils.state import useGlobalState - -from pyopenagi.agents.interact import Interactor +from aios.utils.utils import delete_directories, parse_global_args from pyopenagi.manager.manager import AgentManager -from dotenv import load_dotenv -import warnings - # load the args warnings.filterwarnings("ignore") parser = parse_global_args() @@ -24,23 +21,23 @@ load_dotenv() # start the kernel -llm = useKernel( +llm = useCore( llm_name=args.llm_name, max_gpu_memory=args.max_gpu_memory, eval_device=args.eval_device, max_new_tokens=args.max_new_tokens, - log_mode=args.log_mode, + log_mode=args.llm_core_log_mode, use_backend=args.use_backend, ) # boilerplate from "launch.py" # provides an interface for setting state variables startScheduler, stopScheduler = useFIFOScheduler( - llm=llm, log_mode=args.log_mode, get_queue_message=None + llm=llm, log_mode=args.scheduler_log_mode, get_queue_message=None ) submitAgent, awaitAgentExecution = useFactory( - log_mode=args.log_mode, max_workers=500 + log_mode=args.agent_log_mode, max_workers=500 ) @@ -54,12 +51,13 @@ setManager(AgentManager(args.manager_url)) -WHITE='\033[1m' -GREEN = '\033[32m' -BLUE = '\033[34m' -RED = '\033[31m' -YELLOW = '\033[33m' -RESET = '\033[0m' +WHITE = "\033[1m" +GREEN = "\033[32m" +BLUE = "\033[34m" +RED = "\033[31m" +YELLOW = "\033[33m" +RESET = "\033[0m" + def clean_cache(root_directory): targets = { @@ -79,7 +77,6 @@ def get_all_agents() -> List[str]: return [agent["agent"] for agent in agents] - def display_agents(agents: List[str]): print("Available Agents:") for i, (name) in enumerate(agents, 1): @@ -101,6 +98,7 @@ def get_user_choice(agents: List[Tuple[str, str]]) -> Tuple[str, str]: def get_user_task(chosen_agent) -> str: return input(f"{BLUE}{chosen_agent}:{RESET} ") + def add_agent( agent_name: str, task_input: str, @@ -122,7 +120,6 @@ def execute_agent( return {"success": True, "response": response} - print( """ \033c @@ -199,12 +196,11 @@ def execute_agent( continue print(agent_response["response"]) - + except Exception as e: print(f"An error occurred: {str(e)}") - - + except KeyboardInterrupt: stopScheduler() clean_cache(root_directory="./") diff --git a/agenthub/app/agents/ContentLayout/DatasetsHeader.tsx b/agenthub/app/agents/ContentLayout/DatasetsHeader.tsx index 2b1c0a1fd..43b2d7326 100644 --- a/agenthub/app/agents/ContentLayout/DatasetsHeader.tsx +++ b/agenthub/app/agents/ContentLayout/DatasetsHeader.tsx @@ -2,28 +2,18 @@ import { FilterSVG, SortSVG } from '@/ui/svgs' import { Input } from '@nextui-org/react' -import { AgentListGenerator } from '../const'; +import { useState } from 'react' -import { useState, useEffect } from 'react' +interface DatasetsHeaderProps { + filteredCount?: number; +} -export function DatasetsHeader() { - useEffect(() => { - const _ = async () => { - const AgentList = await AgentListGenerator(); - setAgentNumber(AgentList.length); - } - - _(); - - }, []); - - const [agentNumber, setAgentNumber] = useState(0); - +export function DatasetsHeader({ filteredCount = 0 }: DatasetsHeaderProps) { return (

    Agents

    -
    {agentNumber}
    +
    {filteredCount}
    @@ -44,10 +34,10 @@ export function DatasetsHeader() {
    ) -} \ No newline at end of file +} diff --git a/agenthub/app/agents/TabsLayout/index.client.tsx b/agenthub/app/agents/TabsLayout/index.client.tsx index 4362af95c..e56cb5072 100644 --- a/agenthub/app/agents/TabsLayout/index.client.tsx +++ b/agenthub/app/agents/TabsLayout/index.client.tsx @@ -1,77 +1,95 @@ 'use client' -import { useState } from 'react' +import { useState, useEffect } from 'react' import classNames from 'classnames' - -import { DatasetsTabList } from '../const' -import { DatasetsTabItem } from '../type' - -import FilterTab from './FilterTab' -import TabTasks from './TabTasks' -import TabOther from './TabOther' -import TabLicenses from './TabLicenses' -import TabLanguages from './TabLanguages' -import TabSubTasks from './TabSubTasks' -import TabSizes from './TabSizes' -import { ApplySVG, ExitSVG } from '@/ui/svgs' +import { AgentTabList } from '../const' +import { DatasetsTabItem, AgentItem } from '../type' +import { ExitSVG } from '@/ui/svgs' +import { baseUrl } from '@/lib/env' +import AgentCard from '../ContentLayout/AgentCard' +import { DatasetsHeader } from '../ContentLayout/DatasetsHeader' export default function LeftTabsLayout() { - const [currentTab, setCurrentTab] = useState('Tasks') - //linter - // const [isAddFilterModalDisplay, setIsAddFilterModalDisplay] = useState(false) + const [currentTab, setCurrentTab] = useState('Academic') + const [agents, setAgents] = useState([]) const isAddFilterModalDisplay = false; + useEffect(() => { + const fetchAgents = async () => { + const res = await fetch(`${baseUrl}/api/get_all_agents/light`, { cache: 'no-store' }); + const data = await res.json(); + setAgents(Object.values(data)); + }; + + fetchAgents(); + }, []); + const onTabClick = (tabName: DatasetsTabItem) => { setCurrentTab(tabName) } + // Filter agents based on current selected category + const filteredAgents = agents.filter(agent => { + const name = agent.name.toLowerCase(); + switch(currentTab) { + case 'Academic': + return name.includes('academic') || name.includes('math'); + case 'Creative': + return name.includes('creator') || name.includes('designer') || name.includes('composer'); + case 'Lifestyle': + return name.includes('therapist') || name.includes('trainer') || name.includes('mixologist'); + case 'Entertainment': + return name.includes('entertainment') || name.includes('game'); + default: + return true; + } + }); + return ( -
    -
    -

    Edit Datasets filters

    - -
    -
      - {DatasetsTabList.map((tabName, index) => ( -
    • - -
    • - ))} -
    - -
    - {currentTab === 'Tasks' && } - {currentTab === 'Sizes' && } - {currentTab === 'Sub-tasks' && } - {currentTab === 'Languages' && } - {currentTab === 'Licenses' && } - {currentTab === 'Other' && } -
    -
    - -
    -
    + <> +
    + {/* Left sidebar category menu */} +
    +

    Agent Categories

    + +
    +
      + {AgentTabList.map((tabName, index) => ( +
    • + +
    • + ))} +
    +
    + + {/* Main content section with filtered agents */} +
    + +
    + {filteredAgents.map((agent) => ( + + ))} +
    +
    + ) } diff --git a/agenthub/app/agents/const.ts b/agenthub/app/agents/const.ts index 94236aea7..50d074343 100644 --- a/agenthub/app/agents/const.ts +++ b/agenthub/app/agents/const.ts @@ -12,21 +12,36 @@ export const DatasetList: DatasetItem[] = [...Array(30)].map(() => ({ })) export const AgentList: AgentItem[] = []; -// export const AgentList = +// export const AgentList = export const AgentListGenerator: () => Promise = async () => { - const res = await fetch(`${baseUrl}/api/get_all_agents/light`, { cache: 'no-store' }); - const res_ = await res.json(); + try { + const res = await fetch(`${baseUrl}/api/get_all_agents/light`, { cache: 'no-store' }); + const res_ = await res.json(); - const values: AgentItem[] = Object.values(res_); + if (!res_ || typeof res_ !== 'object') { + console.error('Invalid response format:', res_); + return []; + } - console.log('length', res_) + const values: AgentItem[] = Object.values(res_); + console.log('Response data:', res_); + console.log('Parsed values:', values); - return values; + return values; + } catch (error) { + console.error('Error fetching agents:', error); + return []; + } } // export const DatasetsTabList: DatasetsTabItem[] = ['Tasks', 'Sizes', 'Sub-tasks', 'Languages', 'Licenses', 'Other'] -export const AgentTabList: DatasetsTabItem[] = ['Recommended', 'Writing', 'Entertainment', 'Programming'] +export const AgentTabList: DatasetsTabItem[] = [ + 'Academic', + 'Creative', + 'Lifestyle', + 'Entertainment' +] export const DatasetOther = [ 'Trained with AutoTrain', @@ -380,4 +395,4 @@ export const DatasetLanguages = [ 'xx', 'us', 'ua', -] \ No newline at end of file +] diff --git a/agenthub/app/agents/page.tsx b/agenthub/app/agents/page.tsx index 878d13cda..6be3a9022 100644 --- a/agenthub/app/agents/page.tsx +++ b/agenthub/app/agents/page.tsx @@ -1,16 +1,11 @@ -import TabsLayout from './TabsLayout/index.client' -import ContentLayout from './ContentLayout' +import LeftTabsLayout from './TabsLayout/index.client' -export default function Datasets({ searchParams }: - { searchParams: { [key: string]: string | string[] | undefined } }) { +export default function Datasets() { return ( -
    -
    -
    - - -
    +
    +
    +
    -
    +
    ) -} \ No newline at end of file +} diff --git a/agenthub/app/agents/type.ts b/agenthub/app/agents/type.ts index 01860ec77..67c4fe9b6 100644 --- a/agenthub/app/agents/type.ts +++ b/agenthub/app/agents/type.ts @@ -8,7 +8,9 @@ export interface DatasetItem { favorites: string } -export type AgentTabItem = 'Tasks' | 'Sizes' | 'Sub-tasks' | 'Languages' | 'Licenses' | 'Other' +export type DatasetsTabItem = 'Recommended' | 'Writing' | 'Entertainment' | 'Programming' | 'Tasks' | 'Sizes' | 'Sub-tasks' | 'Languages' | 'Licenses' | 'Other' | 'Academic' | 'Creative' | 'Lifestyle' | 'Entertainment'; + +export type AgentTabItem = 'Tasks' | 'Sizes' | 'Sub-tasks' | 'Languages' | 'Licenses' | 'Other' | 'Academic' | 'Creative' | 'Lifestyle' | 'Entertainment'; export interface AgentItem { @@ -20,4 +22,4 @@ export interface AgentItem { createdAt: string; numDownloads: number; numFavorites: number; -} \ No newline at end of file +} diff --git a/agenthub/app/chat/page.tsx b/agenthub/app/chat/page.tsx index 5f547f80e..8276e0641 100644 --- a/agenthub/app/chat/page.tsx +++ b/agenthub/app/chat/page.tsx @@ -13,27 +13,11 @@ import { AgentCommand } from '@/components/chat/body/message-box'; import { baseUrl, serverUrl } from '@/lib/env'; import { generateSixDigitId } from '@/lib/utils'; - - -const updateChatName = (chatId: number, newName: string) => { - // setChats(prevChats => - // prevChats.map(chat => - // chat.id === chatId ? { ...chat, name: newName } : chat - // ) - // ); -}; - - - - - - - - const ChatInterface: React.FC = () => { - const [messages, setMessages] = useState([]); const [darkMode, setDarkMode] = useState(true); - const [chats, setChats] = useState([{ id: 1, name: 'General' }]); + const [chats, setChats] = useState([ + { id: 1, name: 'General', messages: [] } + ]); const [activeChat, setActiveChat] = useState(1); const messagesEndRef = useRef(null); @@ -62,7 +46,6 @@ const ChatInterface: React.FC = () => { content: string; } - function parseNamedContent(inputString: string) { // Regular expression to match the pattern ?>>Name/?>>\s*Content const regex = /\?>>(.*?)\/?>>([^?]*)/g; @@ -85,53 +68,65 @@ const ChatInterface: React.FC = () => { return results; } - // Ex - - useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); - }, [messages]); + }, [chats]); const handleSend = async (content: string, attachments: File[]) => { if (content.trim() || attachments.length > 0) { const newMessage: Message = { - id: generateSixDigitId(), + id: generateSixDigitId().toString(), text: content, sender: 'user', timestamp: new Date(), attachments: attachments.map(file => file.name), thinking: false }; - setMessages([...messages, newMessage]); - const messageId = generateSixDigitId(); + setChats(prevChats => prevChats.map(chat => + chat.id === activeChat + ? { ...chat, messages: [...chat.messages, newMessage] } + : chat + )); - // Handle file uploads here (e.g., to a server) + const messageId = generateSixDigitId().toString(); const botMessage: Message = { id: messageId, - text: ``, + text: '', sender: 'bot', timestamp: new Date(), thinking: true }; - setMessages(prevMessages => [...prevMessages, botMessage]); - - const res = await processAgentCommand(parseNamedContent(parseText(content))[0] as AgentCommand) - - setMessages(prevMessages => [...prevMessages].map(message => { - if (message.id == messageId) { - return { ...message, thinking: false, text: res.content }; - } - // return res.content; - return message; - })); + setChats(prevChats => prevChats.map(chat => + chat.id === activeChat + ? { ...chat, messages: [...chat.messages, botMessage] } + : chat + )); + + const res = await processAgentCommand(parseNamedContent(parseText(content))[0] as AgentCommand); + + setChats(prevChats => prevChats.map(chat => + chat.id === activeChat + ? { + ...chat, + messages: chat.messages.map(message => + message.id === messageId + ? { ...message, thinking: false, text: res.content } + : message + ) + } + : chat + )); } - }; const addChat = () => { - const newChat: Chat = { id: Date.now(), name: `Chat ${chats.length + 1}` }; + const newChat: Chat = { + id: Date.now(), + name: `Chat ${chats.length + 1}`, + messages: [] + }; setChats([...chats, newChat]); setActiveChat(newChat.id); }; @@ -178,7 +173,6 @@ const ChatInterface: React.FC = () => { recent_response = "Agent Had Difficulty Thinking" } - //return recent_response return { name: command.name, @@ -188,6 +182,29 @@ const ChatInterface: React.FC = () => { const mounted = useMounted(); + const activeMessages = chats.find(chat => chat.id === activeChat)?.messages || []; + + // Add updateChatName function + const updateChatName = (chatId: number, newName: string) => { + setChats(prevChats => + prevChats.map(chat => + chat.id === chatId ? { ...chat, name: newName } : chat + ) + ); + }; + + // Add deleteChat function + const deleteChat = (chatId: number) => { + setChats(prevChats => { + const filteredChats = prevChats.filter(chat => chat.id !== chatId); + // If the deleted chat is the active one, switch to the first chat + if (chatId === activeChat && filteredChats.length > 0) { + setActiveChat(filteredChats[0].id); + } + return filteredChats; + }); + }; + return (
    { setActiveChat={setActiveChat} addChat={addChat} updateChatName={updateChatName} + deleteChat={deleteChat} darkMode={darkMode} />
    -
    - +
    chat.id === activeChat)?.name || 'Chat'} + /> +
    {mounted && }
    @@ -211,5 +233,4 @@ const ChatInterface: React.FC = () => { ); }; - export default ChatInterface; diff --git a/agenthub/components/agentchat/Header.tsx b/agenthub/components/agentchat/Header.tsx index 0064fdd20..aeb8a2468 100644 --- a/agenthub/components/agentchat/Header.tsx +++ b/agenthub/components/agentchat/Header.tsx @@ -5,16 +5,17 @@ import { Sun, Moon, Hash } from 'lucide-react'; export interface HeaderProps { darkMode: boolean; - setDarkMode: React.Dispatch>; + setDarkMode: (value: boolean) => void; + title: string; } -export const Header: React.FC = ({ darkMode, setDarkMode }) => { +export const Header: React.FC = ({ darkMode, setDarkMode, title }) => { const theme = useMantineTheme(); return (
    -

    General

    +

    {title}

    @@ -28,4 +29,4 @@ export const Header: React.FC = ({ darkMode, setDarkMode }) => {
    ); - }; \ No newline at end of file + }; diff --git a/agenthub/components/agentchat/Sidebar.tsx b/agenthub/components/agentchat/Sidebar.tsx index e9496359b..56998246e 100644 --- a/agenthub/components/agentchat/Sidebar.tsx +++ b/agenthub/components/agentchat/Sidebar.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import { TextInput, ActionIcon, Tooltip } from '@mantine/core'; -import { Plus, Hash, Check, Edit2, X } from 'lucide-react'; +import { Plus, Hash, Check, Edit2, X, Trash2 } from 'lucide-react'; import { Chat } from '@/interfaces/agentchat'; @@ -11,50 +11,58 @@ export interface SidebarProps { setActiveChat: (id: number) => void; addChat: () => void; updateChatName: (chatId: number, newName: string) => void; + deleteChat: (chatId: number) => void; darkMode: boolean; } -export const Sidebar: React.FC = ({ chats, activeChat, setActiveChat, addChat, updateChatName, darkMode }) => { +export const Sidebar: React.FC = ({ chats, activeChat, setActiveChat, addChat, updateChatName, deleteChat, darkMode }) => { const [editingId, setEditingId] = useState(null); const [editingName, setEditingName] = useState(''); - + const categoryStyle = "text-xs font-semibold uppercase tracking-wide text-gray-500 mb-2 mt-4 px-2 flex justify-between items-center"; const channelStyle = `flex items-center justify-between rounded px-2 py-1.5 text-sm font-medium transition-colors duration-200 ease-in-out cursor-pointer`; const activeChannelStyle = darkMode ? 'bg-gray-700 text-white' : 'bg-gray-300 text-gray-900'; const inactiveChannelStyle = darkMode ? 'text-gray-400 hover:bg-gray-700 hover:text-gray-200' : 'text-gray-700 hover:bg-gray-200 hover:text-gray-900'; - + const startEditing = (chat: Chat) => { setEditingId(chat.id); setEditingName(chat.name); }; - + const cancelEditing = () => { setEditingId(null); setEditingName(''); }; - + const saveEditing = () => { if (editingId !== null && editingName.trim() !== '') { updateChatName(editingId, editingName.trim()); setEditingId(null); } }; - + + const handleDelete = (chatId: number, e: React.MouseEvent) => { + e.stopPropagation(); + if (window.confirm('Are you sure you want to delete this channel?')) { + deleteChat(chatId); + } + }; + return (

    Your AIOS Workspace

    - +
    Channels - @@ -63,7 +71,7 @@ export const Sidebar: React.FC = ({ chats, activeChat, setActiveCh {chats.map((chat) => (
    {editingId === chat.id ? (
    @@ -89,16 +97,38 @@ export const Sidebar: React.FC = ({ chats, activeChat, setActiveCh {chat.name}
    - - startEditing(chat)} - variant="subtle" - color={darkMode ? "gray" : "dark"} - className="opacity-0 group-hover:opacity-100 transition-opacity duration-200" - > - - - +
    + + { + e.stopPropagation(); + startEditing(chat); + }} + variant="subtle" + color={darkMode ? "gray" : "dark"} + size="sm" + className="ml-1" + > + + + + + handleDelete(chat.id, e)} + variant="subtle" + size="sm" + className="ml-1" + > + + + +
    )}
    @@ -107,3 +137,5 @@ export const Sidebar: React.FC = ({ chats, activeChat, setActiveCh
    ); }; + +export default Sidebar; diff --git a/agenthub/components/homepage/Products.tsx b/agenthub/components/homepage/Products.tsx index b00933763..9325d6921 100644 --- a/agenthub/components/homepage/Products.tsx +++ b/agenthub/components/homepage/Products.tsx @@ -18,7 +18,7 @@ const Examples = [ author_url: 'https://github.com/vercel', author_img: 'https://avatars.githubusercontent.com/u/14985020', repo_name: 'vercel/nextjs-subscription-payments', - repo_url: 'https://my.aios.foundation/agents', + repo_url: 'http://localhost:3000/agents', vercel_deploy_url: 'https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fnextjs-subscription-payments&env=NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY,STRIPE_SECRET_KEY&envDescription=Enter%20your%20Stripe%20API%20keys.&envLink=https%3A%2F%2Fdashboard.stripe.com%2Fapikeys&project-name=nextjs-subscription-payments&repository-name=nextjs-subscription-payments&integration-ids=oac_VqOgBHqhEoFTPzGkPd7L0iH6&external-id=https%3A%2F%2Fgithub.com%2Fvercel%2Fnextjs-subscription-payments%2Ftree%2Fmain', demo_url: 'https://subscription-payments.vercel.app/', @@ -49,7 +49,7 @@ const BuiltWithSupabase = () => {
    Try out our many features
    - +
    {Examples.slice(0, 2).map((example: any, i: number) => { diff --git a/agenthub/interfaces/agentchat.ts b/agenthub/interfaces/agentchat.ts new file mode 100644 index 000000000..b68edeaf1 --- /dev/null +++ b/agenthub/interfaces/agentchat.ts @@ -0,0 +1,14 @@ +export interface Message { + id: string; + text: string; + sender: 'user' | 'bot'; + timestamp: Date; + attachments?: string[]; + thinking?: boolean; +} + +export interface Chat { + id: number; + name: string; + messages: Message[]; +} diff --git a/agenthub/lib/env.ts b/agenthub/lib/env.ts index 1376dba94..d05f10d20 100644 --- a/agenthub/lib/env.ts +++ b/agenthub/lib/env.ts @@ -1,6 +1,9 @@ export const inDevEnvironment = !!process && process.env.NODE_ENV === 'development'; // export const serverUrl = inDevEnvironment ? 'http://localhost:8000' : 'https://myapp-y5z35kuonq-uk.a.run.app' -export const baseUrl = inDevEnvironment ? 'http://localhost:3000' : 'https://my.aios.foundation' +export const baseUrl = process.env.NODE_ENV === 'development' + ? 'http://localhost:3000' + : 'https://my.aios.foundation'; // export const serverUrl = inDevEnvironment ? 'http://localhost:8000' : 'http://35.232.56.61:8000' -export const serverUrl = 'http://35.232.56.61:8000'; - +export const serverUrl = process.env.NODE_ENV === 'development' + ? 'http://localhost:8000' + : 'https://api.aios.chat'; diff --git a/agenthub/public/MentionListV2Light.scss b/agenthub/public/MentionListV2Light.scss index 9cbdf1079..cd52d6728 100644 --- a/agenthub/public/MentionListV2Light.scss +++ b/agenthub/public/MentionListV2Light.scss @@ -10,7 +10,7 @@ overflow: auto; padding: 0.4rem; position: relative; - + button { align-items: center; background-color: transparent; @@ -18,12 +18,16 @@ gap: 0.25rem; text-align: left; width: 100%; - + + .item-text { + color: #000000 !important; + } + &:hover, &:hover.is-selected { background-color: var(--gray-3); } - + &.is-selected { background-color: var(--gray-2); } @@ -34,7 +38,7 @@ :first-child { margin-top: 0; } - + .mention { background-color: var(--purple-light); border-radius: 0.4rem; @@ -50,4 +54,4 @@ box-decoration-break: clone; color: var(--purple); padding: 0.1rem 0.3rem; - } \ No newline at end of file + } diff --git a/aios/hooks/starter.py b/aios/hooks/starter.py index 25afead9d..846406a8b 100644 --- a/aios/hooks/starter.py +++ b/aios/hooks/starter.py @@ -16,7 +16,7 @@ def aios_starter( max_new_tokens: int, scheduler_log_mode: str, agent_log_mode: str, - llm_kernel_log_mode: str, + llm_core_log_mode: str, use_backend: str, ) -> Tuple[Callable[[str, str], int], Callable[[str], Dict[str, Any]]]: """ @@ -40,14 +40,14 @@ def aios_starter( max_gpu_memory=max_gpu_memory, eval_device=eval_device, max_new_tokens=max_new_tokens, - log_mode=llm_kernel_log_mode, + log_mode=llm_core_log_mode, use_backend=use_backend, ) storage_manager = useStorageManager( root_dir = "root", use_vector_db = False ) - + memory_manager = useMemoryManager( memory_limit = 100*1024*1024, eviction_k = 10, @@ -65,9 +65,9 @@ def aios_starter( storage_manager=storage_manager, tool_manager=tool_manager, log_mode=scheduler_log_mode, - get_llm_request=None, - get_memory_request=None, - get_storage_request=None, - get_tool_request=None + get_llm_syscall=None, + get_memory_syscall=None, + get_storage_syscall=None, + get_tool_syscall=None ): yield submit_agent, await_agent_execution diff --git a/aios/hooks/syscall.py b/aios/hooks/syscall.py index fd1985efc..0955376b1 100755 --- a/aios/hooks/syscall.py +++ b/aios/hooks/syscall.py @@ -1,24 +1,20 @@ -from threading import Thread, Lock, Event -from typing import Mapping - -import random import time +from threading import Thread, Event + from aios.hooks.stores._global import ( global_llm_req_queue_add_message, global_memory_req_queue_add_message, global_storage_req_queue_add_message, global_tool_req_queue_add_message, ) +from pyopenagi.utils.chat_template import Request, LLMQuery, MemoryQuery, StorageQuery, ToolQuery -class Syscall(Thread): - def __init__(self, agent_name, query): - """Agent Process +class Message(Request): + pass - Args: - agent_name (str): Name of the agent - query (Query): Query sent by the agent - """ +class Syscall(Thread): + def __init__(self, agent_name, query: Request): super().__init__() self.agent_name = agent_name self.query = query @@ -103,29 +99,33 @@ class StorageSyscall(Syscall): class ToolSyscall(Syscall): - def __init__(self, agent_name, query): - super().__init__(agent_name, query) - self.tool_calls = query + def __init__(self, agent_name, request): + super().__init__(agent_name, request) + self.tool_calls = request def send_request(agent_name, query): - action_type = query.action_type + if isinstance(query, LLMQuery): + action_type = query.action_type + + if action_type == "chat": + return llm_syscall_exec(agent_name, query) - if action_type == "chat": - return llm_syscall_exec(agent_name, query) + elif action_type == "tool_use": + response = llm_syscall_exec(agent_name, query)["response"] + tool_calls = response.tool_calls + return tool_syscall_exec(agent_name, tool_calls) - elif action_type == "tool_use": - response = llm_syscall_exec(agent_name, query)["response"] - tool_calls = response.tool_calls - return tool_syscall_exec(agent_name, tool_calls) + elif action_type == "operate_file": + return storage_syscall_exec(llm_syscall_exec(agent_name, query)) - elif action_type == "operate_file": - return storage_syscall_exec(llm_syscall_exec(agent_name, query)) + elif isinstance(query, ToolQuery): + return tool_syscall_exec(agent_name, query) - elif action_type == "memory_use": - return mem_syscall(agent_name, query) + elif isinstance(query, MemoryQuery): + return mem_syscall_exec(agent_name, query) - elif action_type == "storage_use": + elif isinstance(query, StorageQuery): return storage_syscall_exec(agent_name, query) @@ -173,7 +173,7 @@ def storage_syscall_exec(agent_name, query): } -def mem_syscall(agent_name, query): +def mem_syscall_exec(agent_name, query): syscall = MemSyscall(agent_name, query) syscall.set_status("active") diff --git a/aios/hooks/types/scheduler.py b/aios/hooks/types/scheduler.py index 1205cc3ba..cff02dda4 100644 --- a/aios/hooks/types/scheduler.py +++ b/aios/hooks/types/scheduler.py @@ -1,18 +1,20 @@ +from typing import Any + from pydantic import BaseModel -from typing import Any, TypeAlias, Callable from .llm import LLMRequestQueueGetMessage from .memory import MemoryRequestQueueGetMessage from .storage import StorageRequestQueueGetMessage from .tool import ToolRequestQueueGetMessage + class SchedulerParams(BaseModel): llm: Any memory_manager: Any storage_manager: Any tool_manager: Any log_mode: str - get_llm_request: LLMRequestQueueGetMessage | None - get_memory_request: MemoryRequestQueueGetMessage | None - get_storage_request: StorageRequestQueueGetMessage | None - get_tool_request: ToolRequestQueueGetMessage | None \ No newline at end of file + get_llm_syscall: LLMRequestQueueGetMessage | None + get_memory_syscall: MemoryRequestQueueGetMessage | None + get_storage_syscall: StorageRequestQueueGetMessage | None + get_tool_syscall: ToolRequestQueueGetMessage | None diff --git a/aios/llm_core/llm_classes/base_llm.py b/aios/llm_core/llm_classes/base_llm.py index b77fa90f6..f1018aedf 100644 --- a/aios/llm_core/llm_classes/base_llm.py +++ b/aios/llm_core/llm_classes/base_llm.py @@ -13,13 +13,15 @@ class BaseLLM(ABC): - def __init__(self, - llm_name: str, - max_gpu_memory: dict = None, - eval_device: str = None, - max_new_tokens: int = 256, - log_mode: str = "console" - ): + def __init__( + self, + llm_name: str, + max_gpu_memory: dict = None, + eval_device: str = None, + max_new_tokens: int = 256, + log_mode: str = "console", + use_context_manager: bool = False, + ): self.max_gpu_memory = max_gpu_memory self.eval_device = eval_device self.max_new_tokens = max_new_tokens @@ -27,18 +29,17 @@ def __init__(self, self.log_mode = log_mode self.model_name = llm_name - self.context_manager = SimpleContextManager() + self.use_context_manager = use_context_manager + if use_context_manager: + self.context_manager = SimpleContextManager() self.load_llm_and_tokenizer() self.logger = self.setup_logger() - self.logger.log( - "AIOS has been successfully initialized.\n", - level="info" - ) + self.logger.log("AIOS has been successfully initialized.\n", level="info") def convert_map(self, map: dict) -> dict: - """ helper utility to convert the keys of a map to int """ + """helper utility to convert the keys of a map to int""" new_map = {} for k, v in map.items(): new_map[int(k)] = v @@ -55,8 +56,7 @@ def setup_logger(self): @abstractmethod def load_llm_and_tokenizer(self) -> None: # load model from config # raise NotImplementedError - """Load model and tokenizers for each type of LLMs - """ + """Load model and tokenizers for each type of LLMs""" return # only use for open-sourced LLM @@ -67,12 +67,14 @@ def tool_calling_input_format(self, messages: list, tools: list) -> list: messages (list): messages with different roles tools (list): tool information """ - prefix_prompt = "In and only in current step, you need to call tools. Available tools are: " + prefix_prompt = ( + "In and only in current step, you need to call tools. Available tools are: " + ) tool_prompt = json.dumps(tools) suffix_prompt = "".join( [ - 'Must call functions that are available. To call a function, respond ' - 'immediately and only with a list of JSON object of the following format:' + "Must call functions that are available. To call a function, respond " + "immediately and only with a list of JSON object of the following format:" '{[{"name":"function_name_value","parameters":{"parameter_name1":"parameter_value1",' '"parameter_name2":"parameter_value2"}}]}' ] @@ -86,14 +88,16 @@ def tool_calling_input_format(self, messages: list, tools: list) -> list: message["role"] = "user" tool_call_id = message.pop("tool_call_id") content = message.pop("content") - message["content"] = f"The result of the execution of function(id :{tool_call_id}) is: {content}. " + message["content"] = ( + f"The result of the execution of function(id :{tool_call_id}) is: {content}. " + ) - messages[-1]["content"] += (prefix_prompt + tool_prompt + suffix_prompt) + messages[-1]["content"] += prefix_prompt + tool_prompt + suffix_prompt return messages def parse_json_format(self, message: str) -> str: - json_array_pattern = r'\[\s*\{.*?\}\s*\]' - json_object_pattern = r'\{\s*.*?\s*\}' + json_array_pattern = r"\[\s*\{.*?\}\s*\]" + json_object_pattern = r"\{\s*.*?\s*\}" match_array = re.search(json_array_pattern, message) @@ -116,7 +120,7 @@ def parse_json_format(self, message: str) -> str: return json.dumps(json_object_data) except json.JSONDecodeError: pass - return '[]' + return "[]" def parse_tool_calls(self, message): # add tool call id and type for models don't support tool call @@ -126,14 +130,11 @@ def parse_tool_calls(self, message): tool_call["type"] = "function" return tool_calls - def address_request(self, - agent_request, - temperature=0.0 - ): - return self.process(agent_request) - @abstractmethod - def process(self, - agent_request, - temperature=0.0) -> None: + def address_syscall(self, llm_syscall, temperature=0.0): + # return self.process(llm_syscall) raise NotImplementedError + + # @abstractmethod + # def process(self, agent_request, temperature=0.0) -> None: + # raise NotImplementedError diff --git a/aios/llm_core/llm_classes/gemini_llm.py b/aios/llm_core/llm_classes/gemini_llm.py index f6847f8ff..c7d47645f 100644 --- a/aios/llm_core/llm_classes/gemini_llm.py +++ b/aios/llm_core/llm_classes/gemini_llm.py @@ -8,23 +8,33 @@ import json from pyopenagi.utils.chat_template import Response + + class GeminiLLM(BaseLLM): - def __init__(self, llm_name: str, - max_gpu_memory: dict = None, - eval_device: str = None, - max_new_tokens: int = 256, - log_mode: str = "console"): - super().__init__(llm_name, - max_gpu_memory, - eval_device, - max_new_tokens, - log_mode) + def __init__( + self, + llm_name: str, + max_gpu_memory: dict = None, + eval_device: str = None, + max_new_tokens: int = 256, + log_mode: str = "console", + use_context_manager: bool = False, + ): + super().__init__( + llm_name, + max_gpu_memory, + eval_device, + max_new_tokens, + log_mode, + use_context_manager, + ) def load_llm_and_tokenizer(self) -> None: - """ dynamic loading because the module is only needed for this case """ - assert re.search(r'gemini', self.model_name, re.IGNORECASE) + """dynamic loading because the module is only needed for this case""" + assert re.search(r"gemini", self.model_name, re.IGNORECASE) try: import google.generativeai as genai + gemini_api_key = get_from_env("GEMINI_API_KEY") genai.configure(api_key=gemini_api_key) self.model = genai.GenerativeModel(self.model_name) @@ -42,25 +52,23 @@ def convert_messages(self, messages): gemini_messages.append( { "role": "user" if m["role"] in ["user", "system"] else "model", - "parts": {"text": m["content"]} + "parts": {"text": m["content"]}, } ) else: gemini_messages = None return gemini_messages - def process(self, - agent_request, - temperature=0.0) -> None: + def address_syscall(self, llm_syscall, temperature=0.0) -> None: # ensures the model is the current one - """ wrapper around functions""" + """wrapper around functions""" - agent_request.set_status("executing") - agent_request.set_start_time(time.time()) - messages = agent_request.query.messages - tools = agent_request.query.tools - message_return_type = agent_request.query.message_return_type + llm_syscall.set_status("executing") + llm_syscall.set_start_time(time.time()) + messages = llm_syscall.query.messages + tools = llm_syscall.query.tools + message_return_type = llm_syscall.query.message_return_type if tools: messages = self.tool_calling_input_format(messages, tools) @@ -71,53 +79,38 @@ def process(self, ) self.logger.log( - f"{agent_request.agent_name} is switched to executing.\n", - level = "executing" + f"{llm_syscall.agent_name} is switched to executing.\n", level="executing" ) - outputs = self.model.generate_content( - json.dumps({"contents": messages}) - ) + outputs = self.model.generate_content(json.dumps({"contents": messages})) try: result = outputs.candidates[0].content.parts[0].text if tools: tool_calls = self.parse_tool_calls(result) if tool_calls: - # agent_request.set_response( - # Response( - # response_message=None, - # tool_calls=tool_calls - # ) - # ) response = Response( response_message=None, - tool_calls=tool_calls + tool_calls=tool_calls, + finished=True ) else: - # agent_request.set_response( - - # ) response = Response( response_message=result, + finished=True ) else: if message_return_type == "json": result = self.parse_json_format(result) - - # agent_request.set_response( - # Response( - # response_message=result, - # ) - # ) + response = Response( response_message=result, + finished=True ) - + except IndexError: - raise IndexError(f"{self.model_name} can not generate a valid result, please try again") - - # agent_request.set_status("done") - # agent_request.set_end_time(time.time()) - # return + raise IndexError( + f"{self.model_name} can not generate a valid result, please try again" + ) + return response diff --git a/aios/llm_core/llm_classes/gpt_llm.py b/aios/llm_core/llm_classes/gpt_llm.py index 89f7f98aa..ec1296fe4 100644 --- a/aios/llm_core/llm_classes/gpt_llm.py +++ b/aios/llm_core/llm_classes/gpt_llm.py @@ -20,9 +20,15 @@ def __init__( eval_device: str = None, max_new_tokens: int = 1024, log_mode: str = "console", + use_context_manager: bool = False, ): super().__init__( - llm_name, max_gpu_memory, eval_device, max_new_tokens, log_mode + llm_name, + max_gpu_memory, + eval_device, + max_new_tokens, + log_mode, + use_context_manager, ) def load_llm_and_tokenizer(self) -> None: @@ -46,57 +52,91 @@ def parse_tool_calls(self, tool_calls): return parsed_tool_calls return None - def process(self, agent_request, temperature=0.0): + def address_syscall(self, llm_syscall, temperature=0.0): # ensures the model is the current one assert re.search(r"gpt", self.model_name, re.IGNORECASE) """ wrapper around openai api """ - agent_request.set_status("executing") - agent_request.set_start_time(time.time()) - messages = agent_request.query.messages + llm_syscall.set_status("executing") + llm_syscall.set_start_time(time.time()) try: - response = self.model.chat.completions.create( - model=self.model_name, - messages=messages, - tools=agent_request.query.tools, - # tool_choice = "required" if agent_request.request_data.tools else None, - max_tokens=self.max_new_tokens, - ) - response_message = response.choices[0].message.content - # print(f"[Response] {response}") - tool_calls = self.parse_tool_calls(response.choices[0].message.tool_calls) - # print(tool_calls) - # print(response.choices[0].message) - response = Response( - response_message=response_message, tool_calls=tool_calls - ) + if self.use_context_manager: + response = self.llm_generate(llm_syscall) + else: + query = llm_syscall.query + # print(query) + response = self.model.chat.completions.create( + model=self.model_name, + messages=query.messages, + tools=query.tools, + # tool_choice = "required" if agent_request.request_data.tools else None, + max_tokens=self.max_new_tokens, + ) - except openai.APIConnectionError as e: + response_message = response.choices[0].message.content + + # print(response_message) + tool_calls = self.parse_tool_calls( + response.choices[0].message.tool_calls + ) + response = Response( + response_message=response_message, + tool_calls=tool_calls, + finished=True, + ) + print(response) + + except openai.APIConnectionError as e: response = Response( - response_message=f"Server connection error: {e.__cause__}" + response_message=f"Server connection error: {e.__cause__}", ) except openai.RateLimitError as e: - response = Response( - response_message=f"OpenAI RATE LIMIT error {e.status_code}: (e.response)" + response_message=f"OpenAI RATE LIMIT error {e.status_code}: (e.response)", + finished=True ) except openai.APIStatusError as e: response = Response( - response_message=f"OpenAI STATUS error {e.status_code}: (e.response)" + response_message=f"OpenAI STATUS error {e.status_code}: (e.response)", + finished=True ) except openai.BadRequestError as e: - response = Response( - response_message=f"OpenAI BAD REQUEST error {e.status_code}: (e.response)" + response_message=f"OpenAI BAD REQUEST error {e.status_code}: (e.response)", + finished=True ) except Exception as e: - response = Response(response_message=f"An unexpected error occurred: {e}") + response = Response(response_message=f"An unexpected error occurred: {e}",finished=True) return response - \ No newline at end of file + + def llm_generate(self, llm_syscall, temperature=0.0): + query = llm_syscall.query + if self.context_manager.check_restoration(llm_syscall.get_pid()): + restored_context = self.context_manager.gen_recover(llm_syscall.get_pid()) + + start_time = time.time() + stream = self.model.chat.completions.create( + model=self.model_name, + messages=query.messages + + [{"role": "assistant", "content": "" + restored_context}], + stream=True, + tools=query.tools, + max_tokens=self.max_new_tokens, + ) + + result = "" + for chunk in stream: + if chunk.choices[0].delta.content is not None: + result += chunk.choices[0].delta.content + end_time = time.time() + if end_time - start_time >= llm_syscall.get_time_limit(): + self.context_manager.gen_snapshot(result) + response = Response(response_message=result, finished=False) + return response diff --git a/aios/llm_core/llm_classes/hf_native_llm.py b/aios/llm_core/llm_classes/hf_native_llm.py index df6eaf8f2..da797b164 100644 --- a/aios/llm_core/llm_classes/hf_native_llm.py +++ b/aios/llm_core/llm_classes/hf_native_llm.py @@ -38,31 +38,31 @@ def parse_tool_callings(self, result): matches = re.findall(pattern, result) return matches[-1] - def process(self, - agent_request, + def address_syscall(self, + llm_syscall, temperature=0.0) -> None: - agent_request.set_status("executing") - agent_request.set_start_time(time.time()) + llm_syscall.set_status("executing") + llm_syscall.set_start_time(time.time()) self.logger.log( - f"{agent_request.agent_name} is switched to executing.\n", + f"{llm_syscall.agent_name} is switched to executing.\n", level = "executing" ) - messages = agent_request.request_data.messages - tools = agent_request.request_data.tools - message_return_type = agent_request.request_data.message_return_type + messages = llm_syscall.request_data.messages + tools = llm_syscall.request_data.tools + message_return_type = llm_syscall.request_data.message_return_type """ context_manager works only with open llms """ - if self.context_manager.check_restoration(agent_request.get_pid()): + if self.context_manager.check_restoration(llm_syscall.get_pid()): restored_context = self.context_manager.gen_recover( - agent_request.get_pid() + llm_syscall.get_pid() ) start_idx = restored_context["start_idx"] beams = restored_context["beams"] beam_scores = restored_context["beam_scores"] beam_attention_mask = restored_context["beam_attention_mask"] - outputs = self.generate( + outputs = self.llm_generate( search_mode = "beam_search", beam_size = 1, beams = beams, @@ -70,7 +70,7 @@ def process(self, beam_attention_mask = beam_attention_mask, max_new_tokens = self.max_new_tokens, start_idx = start_idx, - timestamp = agent_request.get_time_limit() + timestamp = llm_syscall.get_time_limit() ) else: """ use the system prompt otherwise """ @@ -89,14 +89,14 @@ def process(self, input_ids = input_ids.to(self.eval_device) attention_mask = attention_mask.to(self.eval_device) - outputs = self.generate( + outputs = self.llm_generate( input_ids = input_ids, attention_mask = attention_mask, search_mode = "beam_search", beam_size = 1, max_new_tokens=self.max_new_tokens, start_idx = 0, - timestamp = agent_request.get_time_limit() + timestamp = llm_syscall.get_time_limit() ) # TODO temporarily outputs["result"] = outputs["result"][input_ids.shape[-1]:] @@ -110,37 +110,37 @@ def process(self, if outputs["finished_flag"]: # finished flag is set as True if self.context_manager.check_restoration( - agent_request.get_pid()): + llm_syscall.get_pid()): self.context_manager.clear_restoration( - agent_request.get_pid() + llm_syscall.get_pid() ) if tools: tool_calls = self.parse_tool_calls( result ) - agent_request.set_response( + llm_syscall.set_response( Response( response_message = None, tool_calls = tool_calls ) ) else: - agent_request.set_response( + llm_syscall.set_response( Response( response_message = result ) ) - agent_request.set_status("done") + llm_syscall.set_status("done") else: """ the module will automatically suspend if reach the time limit """ self.logger.log( - f"{agent_request.agent_name} is switched to suspending due to the reach of time limit ({agent_request.get_time_limit()}s).\n", + f"{llm_syscall.agent_name} is switched to suspending due to the reach of time limit ({llm_syscall.get_time_limit()}s).\n", level = "suspending" ) self.context_manager.gen_snapshot( - agent_request.get_pid(), + llm_syscall.get_pid(), context = { "start_idx": outputs["start_idx"], "beams": outputs["beams"], @@ -150,16 +150,16 @@ def process(self, ) if message_return_type == "json": result = self.parse_json_format(result) - agent_request.set_response( + llm_syscall.set_response( Response( response_message = result ) ) - agent_request.set_status("suspending") + llm_syscall.set_status("suspending") - agent_request.set_end_time(time.time()) + llm_syscall.set_end_time(time.time()) - def generate(self, + def llm_generate(self, input_ids: torch.Tensor = None, attention_mask: torch.Tensor = None, beams: torch.Tensor = None, diff --git a/aios/llm_core/llm_classes/vllm.py b/aios/llm_core/llm_classes/vllm.py index 31de7da78..b95d15b2d 100644 --- a/aios/llm_core/llm_classes/vllm.py +++ b/aios/llm_core/llm_classes/vllm.py @@ -51,19 +51,19 @@ def load_llm_and_tokenizer(self) -> None: max_tokens=self.max_new_tokens, ) - def process(self, - agent_request, + def address_syscall(self, + llm_syscall, temperature=0.0) -> None: - agent_request.set_status("executing") - agent_request.set_start_time(time.time()) + llm_syscall.set_status("executing") + llm_syscall.set_start_time(time.time()) self.logger.log( - f"{agent_request.agent_name} is switched to executing.\n", + f"{llm_syscall.agent_name} is switched to executing.\n", level = "executing" ) - messages = agent_request.request_data.messages - tools = agent_request.request_data.tools - message_return_type = agent_request.request_data.message_return_type + messages = llm_syscall.request_data.messages + tools = llm_syscall.request_data.tools + message_return_type = llm_syscall.request_data.message_return_type if tools: messages = self.tool_calling_input_format(messages, tools) @@ -86,14 +86,14 @@ def process(self, result ) if tool_calls: - agent_request.set_response( + llm_syscall.set_response( Response( response_message = None, tool_calls = tool_calls ) ) else: - agent_request.set_response( + llm_syscall.set_response( Response( response_message = result ) @@ -114,12 +114,12 @@ def process(self, if message_return_type == "json": result = self.parse_json_format(result) - agent_request.set_response( + llm_syscall.set_response( Response( response_message=result ) ) - agent_request.set_status("done") + llm_syscall.set_status("done") - agent_request.set_end_time(time.time()) + llm_syscall.set_end_time(time.time()) diff --git a/aios/llm_core/llms.py b/aios/llm_core/llms.py index 614aae49f..fcb2e11a5 100644 --- a/aios/llm_core/llms.py +++ b/aios/llm_core/llms.py @@ -27,14 +27,16 @@ def __init__(self, eval_device: str = None, max_new_tokens: int = 256, log_mode: str = "console", - use_backend: str = None + use_backend: str = None, + use_context_manager: bool = False ): # For API-based LLM if llm_name in MODEL_REGISTRY.keys(): self.model = MODEL_REGISTRY[llm_name]( llm_name = llm_name, - log_mode = log_mode + log_mode = log_mode, + use_context_manager = use_context_manager ) # For locally-deployed LLM else: @@ -64,8 +66,8 @@ def __init__(self, log_mode=log_mode ) - def address_request(self, - agent_request, + def address_syscall(self, + llm_syscall, temperature=0.0) -> None: """Address request sent from the agent @@ -73,4 +75,4 @@ def address_request(self, agent_request: AgentProcess object that contains request sent from the agent temperature (float, optional): Parameter to control the randomness of LLM output. Defaults to 0.0. """ - return self.model.address_request(agent_request, temperature) + return self.model.address_syscall(llm_syscall, temperature) diff --git a/aios/llm_cores/adapter.py b/aios/llm_cores/adapter.py new file mode 100644 index 000000000..83fb505c2 --- /dev/null +++ b/aios/llm_cores/adapter.py @@ -0,0 +1,80 @@ + +from aios.llm_cores.base import BaseLLM +from aios.llm_cores.registry import API_MODEL_REGISTRY +# from .llm_classes.hf_native_llm import HfNativeLLM + +# standard implementation of LLM methods +# from .llm_classes.ollama_llm import OllamaLLM +# from .llm_classes.vllm import vLLM + +class LLMAdapter: + """Parameters for LLMs + + Args: + llm_name (str): Name of the LLMs + max_gpu_memory (dict, optional): Maximum GPU resources that can be allocated to the LLM. Defaults to None. + eval_device (str, optional): Evaluation device of binding LLM to designated devices for inference. Defaults to None. + max_new_tokens (int, optional): Maximum token length generated by the LLM. Defaults to 256. + log_mode (str, optional): Mode of logging the LLM processing status. Defaults to "console". + use_backend (str, optional): Backend to use for speeding up open-source LLMs. Defaults to None. Choices are ["vllm", "ollama"] + """ + + def __init__(self, + llm_name: str, + max_gpu_memory: dict = None, + eval_device: str = None, + max_new_tokens: int = 256, + use_backend: str = None + ): + + self.model: BaseLLM | None = None + + # For API-based LLM + if llm_name in API_MODEL_REGISTRY.keys(): + self.model = API_MODEL_REGISTRY[llm_name]( + llm_name = llm_name, + ) + # For locally-deployed LLM + else: + if use_backend == "ollama" or llm_name.startswith("ollama"): + # self.model = OllamaLLM( + # llm_name=llm_name, + # max_gpu_memory=max_gpu_memory, + # eval_device=eval_device, + # max_new_tokens=max_new_tokens, + # log_mode=log_mode + # ) + pass + + elif use_backend == "vllm": + # self.model = vLLM( + # llm_name=llm_name, + # max_gpu_memory=max_gpu_memory, + # eval_device=eval_device, + # max_new_tokens=max_new_tokens, + # log_mode=log_mode + # ) + pass + else: # use huggingface LLM without backend + # self.model = HfNativeLLM( + # llm_name=llm_name, + # max_gpu_memory=max_gpu_memory, + # eval_device=eval_device, + # max_new_tokens=max_new_tokens, + # log_mode=log_mode + # ) + pass + + # def execute(self, + # agent_process, + # temperature=0.0) -> None: + # """Address request sent from the agent + + # Args: + # agent_process: AgentProcess object that contains request sent from the agent + # temperature (float, optional): Parameter to control the randomness of LLM output. Defaults to 0.0. + # """ + # self.model.execute(agent_process,temperature) + + def get_model(self) -> BaseLLM | None: + return self.model diff --git a/aios/llm_cores/base.py b/aios/llm_cores/base.py new file mode 100644 index 000000000..2b0024588 --- /dev/null +++ b/aios/llm_cores/base.py @@ -0,0 +1,119 @@ +import json +import re + +# abc allows to make abstract classes +from abc import ABC, abstractmethod + +from aios.utils.id_generator import generator_tool_call_id +from pyopenagi.utils.chat_template import LLMQuery as Query + + +class BaseLLM(ABC): + def __init__(self, + llm_name: str, + max_gpu_memory: dict = None, + eval_device: str = None, + max_new_tokens: int = 256, + ): + self.max_gpu_memory = max_gpu_memory + self.eval_device = eval_device + self.max_new_tokens = max_new_tokens + + self.model_name = llm_name + + self.load_llm_and_tokenizer() + + + + def convert_map(self, map: dict) -> dict: + """ helper utility to convert the keys of a map to int """ + new_map = {} + for k, v in map.items(): + new_map[int(k)] = v + return new_map + + def check_model_type(self, model_name): + # TODO add more model types + return "causal_lm" + + + @abstractmethod + def load_llm_and_tokenizer(self) -> None: # load model from config + # raise NotImplementedError + """Load model and tokenizers for each type of LLMs + """ + return + + # only use for open-sourced LLM + def tool_calling_input_format(self, messages: list, tools: list) -> list: + """Integrate tool information into the messages for open-sourced LLMs + + Args: + messages (list): messages with different roles + tools (list): tool information + """ + prefix_prompt = "In and only in current step, you need to call tools. Available tools are: " + tool_prompt = json.dumps(tools) + suffix_prompt = "".join( + [ + 'Must call functions that are available. To call a function, respond ' + 'immediately and only with a list of JSON object of the following format:' + '{[{"name":"function_name_value","parameters":{"parameter_name1":"parameter_value1",' + '"parameter_name2":"parameter_value2"}}]}' + ] + ) + + # translate tool call message for models don't support tool call + for message in messages: + if "tool_calls" in message: + message["content"] = json.dumps(message.pop("tool_calls")) + elif message["role"] == "tool": + message["role"] = "user" + tool_call_id = message.pop("tool_call_id") + content = message.pop("content") + message["content"] = f"The result of the execution of function(id :{tool_call_id}) is: {content}. " + + messages[-1]["content"] += (prefix_prompt + tool_prompt + suffix_prompt) + return messages + + def parse_json_format(self, message: str) -> str: + json_array_pattern = r'\[\s*\{.*?\}\s*\]' + json_object_pattern = r'\{\s*.*?\s*\}' + + match_array = re.search(json_array_pattern, message) + + if match_array: + json_array_substring = match_array.group(0) + + try: + json_array_data = json.loads(json_array_substring) + return json.dumps(json_array_data) + except json.JSONDecodeError: + pass + + match_object = re.search(json_object_pattern, message) + + if match_object: + json_object_substring = match_object.group(0) + + try: + json_object_data = json.loads(json_object_substring) + return json.dumps(json_object_data) + except json.JSONDecodeError: + pass + return '[]' + + def parse_tool_calls(self, message): + # add tool call id and type for models don't support tool call + tool_calls = json.loads(self.parse_json_format(message)) + for tool_call in tool_calls: + tool_call["id"] = generator_tool_call_id() + tool_call["type"] = "function" + return tool_calls + + def execute(self, query: Query): + return self.process(query) + + @abstractmethod + def process(self, query: Query): + raise NotImplementedError diff --git a/aios/llm_cores/providers/api/anthropic.py b/aios/llm_cores/providers/api/anthropic.py new file mode 100644 index 000000000..1c21f8e03 --- /dev/null +++ b/aios/llm_cores/providers/api/anthropic.py @@ -0,0 +1,158 @@ +import re +import json +import anthropic +from typing import List, Dict, Any + +from cerebrum.llm.base import BaseLLM +from cerebrum.utils.chat import Query, Response + + +class ClaudeLLM(BaseLLM): + """ + ClaudeLLM class for interacting with Anthropic's Claude models. + + This class provides methods for processing queries using Claude models, + including handling of tool calls and message formatting. + + Attributes: + model (anthropic.Anthropic): The Anthropic client for API calls. + tokenizer (None): Placeholder for tokenizer, not used in this implementation. + """ + + def __init__( + self, + llm_name: str, + max_gpu_memory: Dict[int, str] = None, + eval_device: str = None, + max_new_tokens: int = 256, + ): + """ + Initialize the ClaudeLLM instance. + + Args: + llm_name (str): Name of the Claude model to use. + max_gpu_memory (Dict[int, str], optional): GPU memory configuration. + eval_device (str, optional): Device for evaluation. + max_new_tokens (int, optional): Maximum number of new tokens to generate. + log_mode (str, optional): Logging mode, defaults to "console". + """ + super().__init__( + llm_name, + max_gpu_memory=max_gpu_memory, + eval_device=eval_device, + max_new_tokens=max_new_tokens, + ) + + def load_llm_and_tokenizer(self) -> None: + """ + Load the Anthropic client for API calls. + """ + self.model = anthropic.Anthropic() + self.tokenizer = None + + def process(self, query: Query): + """ + Process a query using the Claude model. + + Args: + agent_process (Any): The agent process containing the query and tools. + temperature (float, optional): Sampling temperature for generation. + + Raises: + AssertionError: If the model name doesn't contain 'claude'. + anthropic.APIError: If there's an error with the Anthropic API call. + Exception: For any other unexpected errors. + """ + assert re.search( + r"claude", self.model_name, re.IGNORECASE + ), "Model name must contain 'claude'" + messages = query.messages + tools = query.tools + + print(f"{messages}", level="info") + + if tools: + messages = self.tool_calling_input_format(messages, tools) + + anthropic_messages = self._convert_to_anthropic_messages(messages) + + try: + response = self.model.messages.create( + model=self.model_name, + messages=anthropic_messages, + max_tokens=self.max_new_tokens, + temperature=0.0, + ) + + response_message = response.content[0].text + # self.logger.log(f"API Response: {response_message}", level="info") + tool_calls = self.parse_tool_calls(response_message) if tools else None + + return Response(response_message=response_message, tool_calls=tool_calls) + except anthropic.APIError as e: + error_message = f"Anthropic API error: {str(e)}" + self.logger.log(error_message, level="warning") + return Response(response_message=f"Error: {str(e)}", tool_calls=None) + except Exception as e: + error_message = f"Unexpected error: {str(e)}" + self.logger.log(error_message, level="warning") + return Response( + response_message=f"Unexpected error: {str(e)}", tool_calls=None + ) + + def _convert_to_anthropic_messages( + self, messages: List[Dict[str, str]] + ) -> List[Dict[str, str]]: + """ + Convert messages to the format expected by the Anthropic API. + + Args: + messages (List[Dict[str, str]]): Original messages. + + Returns: + List[Dict[str, str]]: Converted messages for Anthropic API. + """ + anthropic_messages = [] + for message in messages: + if message["role"] == "system": + anthropic_messages.append( + {"role": "user", "content": f"System: {message['content']}"} + ) + anthropic_messages.append( + { + "role": "assistant", + "content": "Understood. I will follow these instructions.", + } + ) + else: + anthropic_messages.append( + { + "role": "user" if message["role"] == "user" else "assistant", + "content": message["content"], + } + ) + return anthropic_messages + + def tool_calling_output_format( + self, tool_calling_messages: str + ) -> List[Dict[str, Any]]: + """ + Parse the tool calling output from the model's response. + + Args: + tool_calling_messages (str): The model's response containing tool calls. + + Returns: + List[Dict[str, Any]]: Parsed tool calls, or None if parsing fails. + """ + try: + json_content = json.loads(tool_calling_messages) + if ( + isinstance(json_content, list) + and len(json_content) > 0 + and "name" in json_content[0] + ): + return json_content + except json.JSONDecodeError: + pass + return super().tool_calling_output_format(tool_calling_messages) diff --git a/aios/hooks/types/hooks.py b/aios/llm_cores/providers/api/bedrock.py similarity index 100% rename from aios/hooks/types/hooks.py rename to aios/llm_cores/providers/api/bedrock.py diff --git a/aios/llm_cores/providers/api/google.py b/aios/llm_cores/providers/api/google.py new file mode 100644 index 000000000..5c152ab1e --- /dev/null +++ b/aios/llm_cores/providers/api/google.py @@ -0,0 +1,100 @@ +# wrapper around gemini from google for LLMs + +import json +import re + +from cerebrum.llm.base import BaseLLM +from cerebrum.utils.chat import Query, Response +from cerebrum.utils.llm import get_from_env + + +class GeminiLLM(BaseLLM): + def __init__(self, llm_name: str, + max_gpu_memory: dict = None, + eval_device: str = None, + max_new_tokens: int = 256,): + super().__init__(llm_name, + max_gpu_memory, + eval_device, + max_new_tokens,) + + def load_llm_and_tokenizer(self) -> None: + """ dynamic loading because the module is only needed for this case """ + assert re.search(r'gemini', self.model_name, re.IGNORECASE) + try: + import google.generativeai as genai + gemini_api_key = get_from_env("GEMINI_API_KEY") + genai.configure(api_key=gemini_api_key) + self.model = genai.GenerativeModel(self.model_name) + self.tokenizer = None + except ImportError: + raise ImportError( + "Could not import google.generativeai python package. " + "Please install it with `pip install google-generativeai`." + ) + + def convert_messages(self, messages): + if messages: + gemini_messages = [] + for m in messages: + gemini_messages.append( + { + "role": "user" if m["role"] in ["user", "system"] else "model", + "parts": {"text": m["content"]} + } + ) + else: + gemini_messages = None + return gemini_messages + + def process(self, query: Query): + # ensures the model is the current one + """ wrapper around functions""" + + # agent_process.set_status("executing") + # agent_process.set_start_time(time.time()) + messages = query.messages + tools = query.tools + message_return_type = query.message_return_type + + if tools: + messages = self.tool_calling_input_format(messages, tools) + + # convert role to fit the gemini role types + messages = self.convert_messages( + messages=messages, + ) + + # self.logger.log( + # f"{agent_process.agent_name} is switched to executing.\n", + # level = "executing" + # ) + + outputs = self.model.generate_content( + json.dumps({"contents": messages}) + ) + + try: + result = outputs.candidates[0].content.parts[0].text + if tools: + tool_calls = self.parse_tool_calls(result) + if tool_calls: + return Response( + response_message=None, + tool_calls=tool_calls + ) + + else: + return Response( + response_message=result, + ) + + else: + if message_return_type == "json": + result = self.parse_json_format(result) + return Response( + response_message=result, + ) + except IndexError: + raise IndexError( + f"{self.model_name} can not generate a valid result, please try again") diff --git a/pyopenagi/agents/experiment/standard/planning/planning_reflexion.py b/aios/llm_cores/providers/api/groq.py similarity index 100% rename from pyopenagi/agents/experiment/standard/planning/planning_reflexion.py rename to aios/llm_cores/providers/api/groq.py diff --git a/aios/llm_cores/providers/api/openai.py b/aios/llm_cores/providers/api/openai.py new file mode 100644 index 000000000..1ca3321b7 --- /dev/null +++ b/aios/llm_cores/providers/api/openai.py @@ -0,0 +1,98 @@ +import json +import re + +from cerebrum.llm.base import BaseLLM +from cerebrum.utils.chat import Query, Response + +import openai +# could be dynamically imported similar to other models +from openai import OpenAI + + +class GPTLLM(BaseLLM): + def __init__(self, llm_name: str, + max_gpu_memory: dict = None, + eval_device: str = None, + max_new_tokens: int = 1024,): + super().__init__(llm_name, + max_gpu_memory, + eval_device, + max_new_tokens,) + + def load_llm_and_tokenizer(self) -> None: + self.model = OpenAI() + self.tokenizer = None + + def parse_tool_calls(self, tool_calls): + if tool_calls: + parsed_tool_calls = [] + for tool_call in tool_calls: + function_name = tool_call.function.name + function_args = json.loads(tool_call.function.arguments) + parsed_tool_calls.append( + { + "name": function_name, + "parameters": function_args, + "type": tool_call.type, + "id": tool_call.id + } + ) + return parsed_tool_calls + return None + + def process(self, query: Query): + # ensures the model is the current one + assert re.search(r'gpt', self.model_name, re.IGNORECASE) + + """ wrapper around openai api """ + # agent_process.set_status("executing") + # agent_process.set_start_time(time.time()) + messages = query.messages + # print(messages) + # self.logger.log( + # f"{agent_process.agent_name} is switched to executing.\n", + # level = "executing" + # ) + # time.sleep(10) + try: + response = self.model.chat.completions.create( + model=self.model_name, + messages=messages, + tools=query.tools, + # tool_choice = "required" if agent_process.query.tools else None, + max_tokens=self.max_new_tokens, + # response_format = {"type": "json_object"} + ) + # print(response_message) + response_message = response.choices[0].message.content + # print(response_message) + tool_calls = self.parse_tool_calls( + response.choices[0].message.tool_calls + ) + # print(tool_calls) + # print(response.choices[0].message) + return Response( + response_message=response_message, + tool_calls=tool_calls + ) + except openai.APIConnectionError as e: + return Response( + response_message=f"Server connection error: {e.__cause__}" + ) + + except openai.RateLimitError as e: + return Response( + response_message=f"OpenAI RATE LIMIT error {e.status_code}: (e.response)" + ) + except openai.APIStatusError as e: + return Response( + response_message=f"OpenAI STATUS error {e.status_code}: (e.response)" + ) + except openai.BadRequestError as e: + return Response( + response_message=f"OpenAI BAD REQUEST error {e.status_code}: (e.response)" + ) + except Exception as e: + return Response( + response_message=f"An unexpected error occurred: {e}" + ) diff --git a/aios/llm_cores/providers/local/huggingface.py b/aios/llm_cores/providers/local/huggingface.py new file mode 100644 index 000000000..e69de29bb diff --git a/aios/llm_cores/providers/local/ollama.py b/aios/llm_cores/providers/local/ollama.py new file mode 100644 index 000000000..e69de29bb diff --git a/aios/llm_cores/providers/local/vllm.py b/aios/llm_cores/providers/local/vllm.py new file mode 100644 index 000000000..e69de29bb diff --git a/aios/llm_cores/registry.py b/aios/llm_cores/registry.py new file mode 100644 index 000000000..4540db29d --- /dev/null +++ b/aios/llm_cores/registry.py @@ -0,0 +1,33 @@ +# registering all proprietary llm models in a constant + + + +#used for closed LLM model registry +from cerebrum.llm.providers.api.anthropic import ClaudeLLM +from cerebrum.llm.providers.api.google import GeminiLLM +from cerebrum.llm.providers.api.openai import GPTLLM + + +API_MODEL_REGISTRY = { + # Gemini + "gemini-1.5-flash": GeminiLLM, + "gemini-1.5-pro": GeminiLLM, + + # GPT + 'gpt-3.5-turbo': GPTLLM, + 'gpt-4-turbo': GPTLLM, + 'gpt-4o': GPTLLM, + 'gpt-4o-2024-05-13': GPTLLM, + 'gpt-4o-mini': GPTLLM, + + # claude + 'claude-3-5-sonnet-20240620': ClaudeLLM, + + # amazon bedrock + # 'bedrock/anthropic.claude-3-haiku-20240307-v1:0': BedrockLLM, + + #Groq + # 'llama3-groq-8b-8192-tool-use-preview': GroqLLM, + # 'llama3-70b-8192': GroqLLM, + # 'mixtral-8x7b-32768' : GroqLLM +} diff --git a/aios/scheduler/base.py b/aios/scheduler/base.py index d8eb383d8..b6ebe47f8 100644 --- a/aios/scheduler/base.py +++ b/aios/scheduler/base.py @@ -1,35 +1,73 @@ -# base implementation of the scheduler, sets up the threads and init -# which all sub classes will inherit and wouldn't need to change. - +from abc import abstractmethod from threading import Thread -from aios.llm_core.llms import LLM - +from aios.hooks.types.llm import LLMRequestQueueGetMessage +from aios.hooks.types.memory import MemoryRequestQueueGetMessage +from aios.hooks.types.storage import StorageRequestQueueGetMessage +from aios.hooks.types.tool import ToolRequestQueueGetMessage from aios.utils.logger import SchedulerLogger -class BaseScheduler: - def __init__(self, llm: LLM, log_mode): - self.active = False # start/stop the scheduler + + +class Scheduler: + def __init__( + self, + llm, + memory_manager, + storage_manager, + tool_manager, + log_mode, + get_llm_syscall: LLMRequestQueueGetMessage, + get_memory_syscall: MemoryRequestQueueGetMessage, + get_storage_syscall: StorageRequestQueueGetMessage, + get_tool_syscall: ToolRequestQueueGetMessage, + ): + # self.agent_process_queue = Queue() + self.get_llm_syscall = get_llm_syscall + self.get_memory_syscall = get_memory_syscall + self.get_storage_syscall = get_storage_syscall + self.get_tool_syscall = get_tool_syscall + self.active = False # start/stop the scheduler self.log_mode = log_mode self.logger = self.setup_logger() - self.thread = Thread(target=self.run) + self.request_processors = { + "llm_syscall_processor": Thread(target=self.run_llm_syscall), + "mem_syscall_processor": Thread(target=self.run_memory_syscall), + "sto_syscall_processor": Thread(target=self.run_storage_syscall), + "tool_syscall_processor": Thread(target=self.run_tool_syscall), + } self.llm = llm - - def run(self): - pass + self.memory_manager = memory_manager + self.storage_manager = storage_manager + self.tool_manager = tool_manager def start(self): """start the scheduler""" self.active = True - self.thread.start() + for name, thread_value in self.request_processors.items(): + thread_value.start() + + def stop(self): + """stop the scheduler""" + self.active = False + for name, thread_value in self.request_processors.items(): + thread_value.join() def setup_logger(self): logger = SchedulerLogger("Scheduler", self.log_mode) return logger - def stop(self): - """stop the scheduler""" - self.active = False - self.thread.join() + @abstractmethod + def run_llm_syscall(self): + pass + + @abstractmethod + def run_memory_syscall(self): + pass + + @abstractmethod + def run_storage_syscall(self): + pass - def execute_request(self, agent_process): + @abstractmethod + def run_tool_syscall(self): pass diff --git a/aios/scheduler/fifo_scheduler.py b/aios/scheduler/fifo_scheduler.py index 8b00193e0..3e0353af1 100644 --- a/aios/scheduler/fifo_scheduler.py +++ b/aios/scheduler/fifo_scheduler.py @@ -7,16 +7,13 @@ from aios.hooks.types.tool import ToolRequestQueueGetMessage from aios.hooks.types.storage import StorageRequestQueueGetMessage -from queue import Queue, Empty +from .base import Scheduler + +from queue import Empty import traceback import time -from aios.utils.logger import SchedulerLogger - -from threading import Thread - - -class FIFOScheduler: +class FIFOScheduler(Scheduler): def __init__( self, llm, @@ -24,70 +21,41 @@ def __init__( storage_manager, tool_manager, log_mode, - get_llm_request: LLMRequestQueueGetMessage, - get_memory_request: MemoryRequestQueueGetMessage, - get_storage_request: StorageRequestQueueGetMessage, - get_tool_request: ToolRequestQueueGetMessage, + get_llm_syscall: LLMRequestQueueGetMessage, + get_memory_syscall: MemoryRequestQueueGetMessage, + get_storage_syscall: StorageRequestQueueGetMessage, + get_tool_syscall: ToolRequestQueueGetMessage, ): - # self.agent_process_queue = Queue() - self.get_llm_request = get_llm_request - self.get_memory_request = get_memory_request - self.get_storage_request = get_storage_request - self.get_tool_request = get_tool_request - self.active = False # start/stop the scheduler - self.log_mode = log_mode - self.logger = self.setup_logger() - self.request_processors = { - "llm_syscall_processor": Thread(target=self.run_llm_request), - "mem_syscall_processor": Thread(target=self.run_memory_request), - "sto_syscall_processor": Thread(target=self.run_storage_request), - "tool_syscall_processor": Thread(target=self.run_tool_request) - } - self.llm = llm - self.memory_manager = memory_manager - self.storage_manager = storage_manager - self.tool_manager = tool_manager - - def start(self): - """start the scheduler""" - self.active = True - for name, thread_value in self.request_processors.items(): - thread_value.start() - - def stop(self): - """stop the scheduler""" - self.active = False - for name, thread_value in self.request_processors.items(): - thread_value.join() - - def setup_logger(self): - logger = SchedulerLogger("Scheduler", self.log_mode) - return logger - - def run_llm_request(self): + super().__init__( + llm, + memory_manager, + storage_manager, + tool_manager, + log_mode, + get_llm_syscall, + get_memory_syscall, + get_storage_syscall, + get_tool_syscall, + ) + + def run_llm_syscall(self): while self.active: try: # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty - agent_request = self.get_llm_request() + llm_syscall = self.get_llm_syscall() - agent_request.set_status("executing") + llm_syscall.set_status("executing") self.logger.log( - f"{agent_request.agent_name} is executing. \n", "execute" + f"{llm_syscall.agent_name} is executing. \n", "execute" ) - agent_request.set_start_time(time.time()) + llm_syscall.set_start_time(time.time()) - response = self.llm.address_request(agent_request) - agent_request.set_response(response) + response = self.llm.address_syscall(llm_syscall) + llm_syscall.set_response(response) - agent_request.event.set() - agent_request.set_status("done") - agent_request.set_end_time(time.time()) - - # self.logger.log( - # f"Current request of {agent_request.agent_name} is done. Thread ID is {agent_request.get_pid()}\n", - # "done", - # ) - # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty + llm_syscall.event.set() + llm_syscall.set_status("done") + llm_syscall.set_end_time(time.time()) except Empty: pass @@ -95,98 +63,75 @@ def run_llm_request(self): except Exception: traceback.print_exc() - def run_memory_request(self): + def run_memory_syscall(self): while self.active: try: # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty - agent_request = self.get_memory_request() + memory_syscall = self.get_memory_syscall() - agent_request.set_status("executing") + memory_syscall.set_status("executing") self.logger.log( - f"{agent_request.agent_name} is executing. \n", "execute" + f"{memory_syscall.agent_name} is executing. \n", "execute" ) - agent_request.set_start_time(time.time()) - - response = self.memory_manager.address_request(agent_request) - agent_request.set_response(response) + memory_syscall.set_start_time(time.time()) - # self.llm.address_request(agent_request) + response = self.memory_manager.address_request(memory_syscall) + memory_syscall.set_response(response) - agent_request.event.set() - agent_request.set_status("done") - agent_request.set_end_time(time.time()) - - # self.logger.log( - # f"Current request of {agent_request.agent_name} is done. Thread ID is {agent_request.get_pid()}\n", - # "done", - # ) - # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty + memory_syscall.event.set() + memory_syscall.set_status("done") + memory_syscall.set_end_time(time.time()) except Empty: pass except Exception: traceback.print_exc() - - def run_storage_request(self): + + def run_storage_syscall(self): while self.active: try: - # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty - agent_request = self.get_storage_request() + storage_syscall = self.get_storage_syscall() - agent_request.set_status("executing") + storage_syscall.set_status("executing") self.logger.log( - f"{agent_request.agent_name} is executing. \n", "execute" + f"{storage_syscall.agent_name} is executing. \n", "execute" ) - agent_request.set_start_time(time.time()) + storage_syscall.set_start_time(time.time()) - response = self.storage_manager.address_request(agent_request) - agent_request.set_response(response) + response = self.storage_manager.address_request(storage_syscall) + storage_syscall.set_response(response) - # self.llm.address_request(agent_request) - - agent_request.event.set() - agent_request.set_status("done") - agent_request.set_end_time(time.time()) + storage_syscall.event.set() + storage_syscall.set_status("done") + storage_syscall.set_end_time(time.time()) self.logger.log( - f"Current request of {agent_request.agent_name} is done. Thread ID is {agent_request.get_pid()}\n", - "done", + f"Current request of {storage_syscall.agent_name} is done. Thread ID is {storage_syscall.get_pid()}\n", + "done" ) - # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty except Empty: pass except Exception: traceback.print_exc() - - def run_tool_request(self): + + def run_tool_syscall(self): while self.active: try: - # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty - agent_request = self.get_tool_request() + tool_syscall = self.get_tool_syscall() - agent_request.set_status("executing") - # self.logger.log( - # f"{agent_request.agent_name} is executing. \n", "execute" - # ) - agent_request.set_start_time(time.time()) + tool_syscall.set_status("executing") - response = self.tool_manager.address_request(agent_request) - agent_request.set_response(response) + tool_syscall.set_start_time(time.time()) - # self.llm.address_request(agent_request) + response = self.tool_manager.address_request(tool_syscall) + tool_syscall.set_response(response) - agent_request.event.set() - agent_request.set_status("done") - agent_request.set_end_time(time.time()) - - # self.logger.log( - # f"Current request of {agent_request.agent_name} is done. Thread ID is {agent_request.get_pid()}\n", - # "done", - # ) - # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty + tool_syscall.event.set() + tool_syscall.set_status("done") + tool_syscall.set_end_time(time.time()) except Empty: pass diff --git a/aios/scheduler/rr_scheduler.py b/aios/scheduler/rr_scheduler.py index 3142b79a5..ca8a20083 100644 --- a/aios/scheduler/rr_scheduler.py +++ b/aios/scheduler/rr_scheduler.py @@ -2,100 +2,72 @@ # Allows multiple agents to run at the same time, with each getting a fixed # chunk of processor time -from .base import BaseScheduler - # allows for memory to be shared safely between threads -from queue import Queue, Empty -from ..context.simple_context import SimpleContextManager +import time +import traceback +from queue import Empty from aios.hooks.types.llm import LLMRequestQueueGetMessage from aios.hooks.types.memory import MemoryRequestQueueGetMessage -from aios.hooks.types.tool import ToolRequestQueueGetMessage from aios.hooks.types.storage import StorageRequestQueueGetMessage - -from queue import Queue, Empty - -import traceback -import time -from aios.utils.logger import SchedulerLogger - -from threading import Thread +from aios.hooks.types.tool import ToolRequestQueueGetMessage +from .base import Scheduler +from ..context.simple_context import SimpleContextManager -class RRScheduler: +class RRScheduler(Scheduler): def __init__( self, llm, - # memory_manager, + memory_manager, + storage_manager, + tool_manager, log_mode, - get_llm_request: LLMRequestQueueGetMessage, - get_memory_request: MemoryRequestQueueGetMessage, - get_storage_request: StorageRequestQueueGetMessage, - get_tool_request: ToolRequestQueueGetMessage, + get_llm_syscall: LLMRequestQueueGetMessage, + get_memory_syscall: MemoryRequestQueueGetMessage, + get_storage_syscall: StorageRequestQueueGetMessage, + get_tool_syscall: ToolRequestQueueGetMessage, ): - self.agent_process_queue = Queue() - self.get_llm_request = get_llm_request - self.get_memory_request = get_memory_request - self.get_storage_request = get_storage_request - self.get_tool_request = get_tool_request - self.active = False # start/stop the scheduler - self.log_mode = log_mode - self.logger = self.setup_logger() - # self.thread = Thread(target=self.run) - self.request_processors = { - "llm_syscall_processor": Thread(target=self.run_llm_request), - "mem_syscall_processor": Thread(target=self.run_memory_request), - "sto_syscall_processor": Thread(target=self.run_storage_request), - "tool_syscall_processor": Thread(target=self.run_tool_request) - # "memory_request_processor": Thread(self.run_memory_request) - } + super().__init__( + llm, + memory_manager, + storage_manager, + tool_manager, + log_mode, + get_llm_syscall, + get_memory_syscall, + get_storage_syscall, + get_tool_syscall, + ) self.llm = llm - self.time_limit = 5 + self.time_limit = 0.5 self.simple_context_manager = SimpleContextManager() - # self.memory_manager = memory_manager - - def start(self): - """start the scheduler""" - self.active = True - for name, thread_value in self.request_processors.items(): - thread_value.start() - - def stop(self): - """stop the scheduler""" - self.active = False - for name, thread_value in self.request_processors.items(): - thread_value.join() - - def setup_logger(self): - logger = SchedulerLogger("Scheduler", self.log_mode) - return logger def run_llm_request(self): while self.active: try: - # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty - agent_request = self.get_llm_request() + llm_syscall = self.get_llm_request() - agent_request.set_status("executing") + llm_syscall.set_status("executing") self.logger.log( - f"{agent_request.agent_name} is executing. \n", "execute" + f"{llm_syscall.agent_name} is executing. \n", "execute" ) - agent_request.set_start_time(time.time()) + llm_syscall.set_start_time(time.time()) - response = self.llm.address_request(agent_request) - agent_request.set_response(response) + response = self.llm.address_request(llm_syscall) + llm_syscall.set_response(response) # self.llm.address_request(agent_request) - agent_request.event.set() - agent_request.set_status("done") - agent_request.set_end_time(time.time()) + llm_syscall.event.set() + llm_syscall.set_status("done") + llm_syscall.set_end_time(time.time()) self.logger.log( - f"Current request of {agent_request.agent_name} is done. Thread ID is {agent_request.get_pid()}\n", + f"Current request of {llm_syscall.agent_name} is done. Thread ID is {llm_syscall.get_pid()}\n", "done", ) # wait at a fixed time interval, if there is nothing received in the time interval, it will raise Empty @@ -138,7 +110,7 @@ def run_memory_request(self): except Exception: traceback.print_exc() - + def run_storage_request(self): while self.active: try: @@ -171,7 +143,7 @@ def run_storage_request(self): except Exception: traceback.print_exc() - + def run_tool_request(self): while self.active: try: @@ -204,4 +176,3 @@ def run_tool_request(self): except Exception: traceback.print_exc() - diff --git a/aios/sdk/autogen/client_adapter.py b/aios/sdk/autogen/client_adapter.py index c0c5539c2..592251e40 100644 --- a/aios/sdk/autogen/client_adapter.py +++ b/aios/sdk/autogen/client_adapter.py @@ -15,7 +15,7 @@ from openai import APITimeoutError, APIError from aios.hooks.syscall import send_request -from pyopenagi.utils.chat_template import Query +from pyopenagi.utils.chat_template import LLMQuery try: from autogen import ( @@ -138,13 +138,13 @@ def adapter_client_create(self, **config: Any) -> ModelClient.ModelClientRespons continue # filter is not passed; try the next config try: request_ts = get_current_ts() - response, start_times, end_times, waiting_times, turnaround_times = send_request( + response = send_request( agent_name="AutoGen", - query=Query( + query=LLMQuery( messages=params['messages'], tools=(params["tools"] if "tools" in params else None) ) - ) + )["response"] response = {'content': response.response_message, 'tool_calls': response.tool_calls} except APITimeoutError as err: logger.debug(f"config {i} timed out", exc_info=True) diff --git a/aios/sdk/interpreter/adapter.py b/aios/sdk/interpreter/adapter.py index 9c7ec51c1..e790e9d96 100644 --- a/aios/sdk/interpreter/adapter.py +++ b/aios/sdk/interpreter/adapter.py @@ -6,7 +6,7 @@ from aios.hooks.syscall import send_request from aios.sdk.adapter import add_framework_adapter from aios.utils.logger import SDKLogger -from pyopenagi.utils.chat_template import Query +from pyopenagi.utils.chat_template import LLMQuery from dataclasses import dataclass try: @@ -66,13 +66,13 @@ def adapter_aios_completions(**params): for attempt in range(attempts): try: - response, _, _, _, _ = send_request( + response = send_request( agent_name="Open-Interpreter", - query=Query( + query=LLMQuery( messages=params['messages'], tools=(params["tools"] if "tools" in params else None) ) - ) + )["response"] # format similar to completion in interpreter comletion = {'choices': diff --git a/aios/sdk/metagpt/adapter.py b/aios/sdk/metagpt/adapter.py index a1f64de71..6fb6bb0d7 100644 --- a/aios/sdk/metagpt/adapter.py +++ b/aios/sdk/metagpt/adapter.py @@ -2,7 +2,7 @@ # Adapte metagpt to run LLM in aios from typing import Union, Optional from aios.utils.logger import SDKLogger -from pyopenagi.utils.chat_template import Query +from pyopenagi.utils.chat_template import LLMQuery from .config_adapter import prepare_metagpt_config from ..adapter import add_framework_adapter from ...hooks.syscall import send_request @@ -74,7 +74,7 @@ async def adapter_acompletion_text( # call aios for response response, _, _, _, _ = send_request( agent_name="MetaGPT", - query=Query( + query=LLMQuery( messages=messages, tools=None ) diff --git a/aios/tool/manager.py b/aios/tool/manager.py index 77e64ec35..3f273cbec 100644 --- a/aios/tool/manager.py +++ b/aios/tool/manager.py @@ -26,9 +26,10 @@ def address_request(self, syscall) -> None: tool_result = tool.run(params=tool_params) self.tool_conflict_map.pop(tool_org_and_name) - + return Response( - response_message=tool_result + response_message=tool_result, + finished=True ) def load_tool_instance(self, tool_org_and_name): diff --git a/aios/utils/utils.py b/aios/utils/utils.py index 72ede2c99..e01dfef30 100755 --- a/aios/utils/utils.py +++ b/aios/utils/utils.py @@ -26,7 +26,7 @@ def parse_global_args(): # parser.add_argument("--log_mode", type=str, default="console", choices=["console", "file"]) parser.add_argument("--scheduler_log_mode", type=str, default="console", choices=["console", "file"], help="Log mode for the scheduler") parser.add_argument("--agent_log_mode", type=str, default="console", choices=["console", "file"], help="Log mode for the agents") - parser.add_argument("--llm_kernel_log_mode", type=str, default="console", choices=["console", "file"], help="Log mode for the LLM kernel") + parser.add_argument("--llm_core_log_mode", type=str, default="console", choices=["console", "file"], help="Log mode for the LLM kernel") parser.add_argument("--use_backend", type=str, choices=["ollama", "vllm"], help="Backend to use for running the LLM kernel") return parser def extract_before_parenthesis(s: str) -> str: diff --git a/experiment/agent/autogen.py b/experiment/agent/autogen.py index db0e8b4be..417e11ae7 100644 --- a/experiment/agent/autogen.py +++ b/experiment/agent/autogen.py @@ -4,11 +4,11 @@ from autogen import ConversableAgent from aios.sdk import prepare_framework, FrameworkType -from experiment.agent.experiment_agent import ExpirementAgent +from experiment.agent.experiment_agent import ExperimentAgent from pyopenagi.tools.arxiv.arxiv import Arxiv -class AutoGenAgent(ExpirementAgent): +class AutoGenAgent(ExperimentAgent): _TERMINATION = "" def __init__(self, on_aios: bool = True): @@ -40,7 +40,7 @@ def run(self, input_str: str): return "" -class AutoGenAgentGAIA(ExpirementAgent): +class AutoGenAgentGAIA(ExperimentAgent): SYSTEM_PROMPT = """You are a general AI assistant. I will ask you a question. Report your thoughts, and finish your answer with the following template: FINAL ANSWER: [YOUR FINAL ANSWER]. @@ -93,7 +93,7 @@ def run(self, input_str: str): return "" -class AutoGenAgentHumanEval(ExpirementAgent): +class AutoGenAgentHumanEval(ExperimentAgent): SYSTEM_PROMPT = """You are an AI assistant good at coding. You will receive a function definition and comments. You need to help me complete this function. I will help you check your code. If you think it is ok to diff --git a/experiment/agent/interpreter.py b/experiment/agent/interpreter.py index 20d1aafbf..27e3d0e4d 100644 --- a/experiment/agent/interpreter.py +++ b/experiment/agent/interpreter.py @@ -4,10 +4,10 @@ from interpreter import interpreter from aios.sdk import prepare_framework, FrameworkType -from experiment.agent.experiment_agent import ExpirementAgent +from experiment.agent.experiment_agent import ExperimentAgent -class InterpreterAgent(ExpirementAgent): +class InterpreterAgent(ExperimentAgent): SYSTEM_PROMPT_WRITE = """\n You can try writing some code to solve the problem, but please note that you are not in the problem repository. Must write your final patch into patch.diff. If code is hard to run, just write the patch you @@ -61,9 +61,9 @@ def run(self, input_str: str): return result_content -class InterpreterAgentHumanEval(ExpirementAgent): +class InterpreterAgentHumanEval(ExperimentAgent): - SYSTEM_PROMPT = """You are an expert good at solving code problems. + SYSTEM_PROMPT = """You are an expert good at solving code problems. You will receive a function definition and comments. You need to help me complete this function. Give me final output in the format: diff --git a/experiment/agent/metagpt.py b/experiment/agent/metagpt.py index b47ec618b..6d39455e7 100644 --- a/experiment/agent/metagpt.py +++ b/experiment/agent/metagpt.py @@ -1,10 +1,10 @@ from metagpt.software_company import generate_repo, ProjectRepo from aios.sdk.metagpt.adapter import prepare_metagpt -from experiment.agent.experiment_agent import ExpirementAgent +from experiment.agent.experiment_agent import ExperimentAgent -class MetaGPTAgent(ExpirementAgent): +class MetaGPTAgent(ExperimentAgent): def __init__(self): prepare_metagpt() diff --git a/experiment/gaia/inference.py b/experiment/gaia/inference.py index 367f29239..f9379406a 100644 --- a/experiment/gaia/inference.py +++ b/experiment/gaia/inference.py @@ -3,9 +3,10 @@ from typing import List from datasets import load_dataset + from aios.hooks.starter import aios_starter -from experiment.agent.experiment_agent import ExpirementAgent -from experiment.experiment_core import MetaData, run_inference, AGENT_TYPE_MAPPING_AIOS, logger +from experiment.agent.experiment_agent import ExperimentAgent +from experiment.experiment_core import MetaData, AGENT_TYPE_MAPPING_AIOS, logger from experiment.utils import get_args @@ -18,7 +19,7 @@ def write_output_func(result_list: List, output_file: str): def process_one_func(data, meta_data: MetaData): if meta_data.on_aios: with aios_starter(**meta_data.aios_args): - agent: ExpirementAgent = AGENT_TYPE_MAPPING_AIOS[meta_data.agent_type](meta_data.on_aios) + agent: ExperimentAgent = AGENT_TYPE_MAPPING_AIOS[meta_data.agent_type](meta_data.on_aios) result = agent.run(data["Question"]) match = re.search(r'FINAL ANSWER: (.+)', result) @@ -31,7 +32,7 @@ def process_one_func(data, meta_data: MetaData): } return prediction else: - agent: ExpirementAgent = AGENT_TYPE_MAPPING_AIOS[meta_data.agent_type](meta_data.on_aios) + agent: ExperimentAgent = AGENT_TYPE_MAPPING_AIOS[meta_data.agent_type](meta_data.on_aios) result = agent.run(data["Question"]) match = re.search(r'FINAL ANSWER: (.+)', result) @@ -51,17 +52,19 @@ def process_one_func(data, meta_data: MetaData): agent_type = "gaia:" + main_args.agent_type dataset = load_dataset(main_args.data_name, "2023_all", split=main_args.split) - meta = MetaData( - dataset=dataset, - agent_type=agent_type, - output_file=main_args.output_file, - on_aios=main_args.on_aios, - max_num=main_args.max_num, - aios_args=vars(global_args), - ) - - run_inference( - meta_data=meta, - process_one_func=process_one_func, - write_output_func=write_output_func, - ) + print(dataset[:1]) + + # meta = MetaData( + # dataset=dataset, + # agent_type=agent_type, + # output_file=main_args.output_file, + # on_aios=main_args.on_aios, + # max_num=main_args.max_num, + # aios_args=vars(global_args), + # ) + + # run_inference( + # meta_data=meta, + # process_one_func=process_one_func, + # write_output_func=write_output_func, + # ) diff --git a/main.py b/main.py index cea2c1c6b..9ae38285a 100644 --- a/main.py +++ b/main.py @@ -37,7 +37,7 @@ def main(): # register your agents and submit agent tasks agent_tasks = [ - ["example/academic_agent", "Tell me what is the prollm paper mainly about"], + ["example/academic_agent", "Tell me what is the prollm paper mainly about? "], # [ # "example/cocktail_mixlogist", # "Create a cocktail for a summer garden party. Guests enjoy refreshing, citrusy flavors. Available ingredients include vodka, gin, lime, lemon, mint, and various fruit juices.", @@ -90,4 +90,4 @@ def main(): if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/pyopenagi/agents/example/seeact_agent/agent.py b/pyopenagi/agents/example/seeact_agent/agent.py index 95e93848a..fa8a54e03 100644 --- a/pyopenagi/agents/example/seeact_agent/agent.py +++ b/pyopenagi/agents/example/seeact_agent/agent.py @@ -1,9 +1,11 @@ import time -from pyopenagi.utils.logger import AgentLogger + from seeact.agent import SeeActAgent as SeeActCore -from seeact.demo_utils.inference_engine import Engine -from pyopenagi.utils.chat_template import Query -from aios.hooks.request import send_request + +from aios.hooks.syscall import send_request +from pyopenagi.utils.chat_template import LLMQuery +from pyopenagi.utils.logger import AgentLogger + class SeeActAgent: def __init__(self, agent_name, task_input, log_mode: str): @@ -29,7 +31,7 @@ def __init__(self, agent_name, task_input, log_mode: str): ) # Replace the generate method - def custom_generate(self_engine, prompt: list = None, max_new_tokens=4096, temperature=None, + def custom_generate(self_engine, prompt: list = None, max_new_tokens=4096, temperature=None, model=None, image_path=None, ouput_0=None, turn_number=0, **kwargs): try: # Keep the original rate limiting logic @@ -59,14 +61,14 @@ def custom_generate(self_engine, prompt: list = None, max_new_tokens=4096, tempe ] # Use correct message format and return value handling - response, start_times, end_times, waiting_times, turnaround_times = send_request( + response = send_request( agent_name=agent_name, - query=Query( + query=LLMQuery( messages=prompt_input, tools=None, message_return_type="json" ) - ) + )["response"] # Update rate limiting time if self_engine.request_interval > 0: @@ -76,14 +78,14 @@ def custom_generate(self_engine, prompt: list = None, max_new_tokens=4096, tempe ) return response.response_message - + except Exception as e: print(f"Error in generate: {str(e)}") raise # Replace the engine's generate method self.seeact.engine.generate = custom_generate.__get__(self.seeact.engine) - + self.start_time = None self.end_time = None self.created_time = time.time() @@ -92,7 +94,7 @@ async def run(self): try: self.start_time = time.time() await self.seeact.start() - + while not self.seeact.complete_flag: try: prediction_dict = await self.seeact.predict() @@ -100,16 +102,16 @@ async def run(self): await self.seeact.execute(prediction_dict) except Exception as e: self.logger.log(f"Error occurred: {e}", "info") - + await self.seeact.stop() self.end_time = time.time() - + return { "agent_name": self.agent_name, "result": "Task completed", "turnaround_time": self.end_time - self.start_time } - + except Exception as e: self.logger.log(f"Error in run method: {str(e)}", "info") return { @@ -118,4 +120,4 @@ async def run(self): } # Register the agent -SeeactAgent = SeeActAgent \ No newline at end of file +SeeactAgent = SeeActAgent diff --git a/pyopenagi/agents/experiment/standard/action/action_code.py b/pyopenagi/agents/experiment/standard/action/code.py similarity index 68% rename from pyopenagi/agents/experiment/standard/action/action_code.py rename to pyopenagi/agents/experiment/standard/action/code.py index 43d4812c7..601664fb9 100644 --- a/pyopenagi/agents/experiment/standard/action/action_code.py +++ b/pyopenagi/agents/experiment/standard/action/code.py @@ -2,14 +2,24 @@ from pyopenagi.agents.experiment.standard.environment.code_environment import CodeEnvironment CODE_PROMPT = """You can write code to solve problem. If you want to write code to solve problem, surrounding your -code with a code block. A code block should like: +code with a code block. A perfect code should contains +- a function defination, like: + def calculate(a: int, b: int): + return a + b +- a call of function, like: + a = 5 + b = 10 + result = calculate(a, b) + print(f"Code execute result is: {result}") +A code block should like: ```python -def main(): - print("hello") +def calculate(a: int, b: int): + return a + b -if __name__ == '__main__': - main() +a = 5 +b = 10 +print(f"Code execute result is: {calculate(a, b)}") ``` If additional dependencies are required, please provid the command install them, format like: @@ -55,10 +65,18 @@ def execute_code(self, code: str, requirements: str): return init_err exec_res = self.environment.step(code) - return exec_res + code_str = (f"###############Code###############\n" + f"{code}\n" + f"###############Code###############\n" + f"Code execute result is :{exec_res}") + return code_str, None def format_prompt(self): return { "name": "code", "description": CODE_PROMPT } + + @staticmethod + def display(): + return True diff --git a/pyopenagi/agents/experiment/standard/action/action_tool.py b/pyopenagi/agents/experiment/standard/action/tool.py similarity index 100% rename from pyopenagi/agents/experiment/standard/action/action_tool.py rename to pyopenagi/agents/experiment/standard/action/tool.py diff --git a/pyopenagi/agents/experiment/standard/agent.py b/pyopenagi/agents/experiment/standard/agent.py index f3093388b..f24dcaa68 100644 --- a/pyopenagi/agents/experiment/standard/agent.py +++ b/pyopenagi/agents/experiment/standard/agent.py @@ -1,8 +1,8 @@ import time from typing import List from aios.hooks.syscall import send_request -from pyopenagi.agents.experiment.standard.action.action_code import ActionCode -from pyopenagi.agents.experiment.standard.action.action_tool import ActionTool +from pyopenagi.agents.experiment.standard.action.code import ActionCode +from pyopenagi.agents.experiment.standard.action.tool import ActionTool from pyopenagi.agents.experiment.standard.environment.code_environment import LocalCodeEnvironment from pyopenagi.agents.experiment.standard.memory.short_term_memory import ShortTermMemory from pyopenagi.agents.experiment.standard.planning.planning import Planning, DefaultPlanning @@ -137,7 +137,10 @@ def run(self): action_param = planning_result.action_param response, tool_call_id = action(**action_param) - self.short_term_memory.remember("assistant", response, tool_call_id) + if planning_result.text_content: + self.short_term_memory.remember("assistant", planning_result.text_content) + self.log_last_message() + self.short_term_memory.remember("user", response, tool_call_id) else: response = planning_result.text_content @@ -156,7 +159,7 @@ def request(self, messages: List, tools: List) -> Response: agent_name=self.agent_name, query=LLMQuery( messages=messages, - tools=tools, + tools=tools if tools else None, ) ) diff --git a/pyopenagi/agents/experiment/standard/communication/communication.py b/pyopenagi/agents/experiment/standard/communication/communication.py index f6e55bb91..dbe8aa5a0 100644 --- a/pyopenagi/agents/experiment/standard/communication/communication.py +++ b/pyopenagi/agents/experiment/standard/communication/communication.py @@ -1,10 +1,12 @@ -from abc import ABC +from abc import ABC, abstractmethod class Communication(ABC): + @abstractmethod def send(self, *args, **kwargs): pass + @abstractmethod def receive(self, *args, **kwargs): pass diff --git a/pyopenagi/agents/experiment/standard/communication/message_pool.py b/pyopenagi/agents/experiment/standard/communication/message_pool.py new file mode 100644 index 000000000..2de312eac --- /dev/null +++ b/pyopenagi/agents/experiment/standard/communication/message_pool.py @@ -0,0 +1,24 @@ +import threading +import queue +from typing import Any + +from pyopenagi.agents.experiment.standard.communication.communication import Communication + +SHARED_DICT: dict[Any, queue] = {} + + +class MessagePool(Communication): + _pool: dict[Any, queue] = SHARED_DICT + + def __init__(self): + super().__init__() + self._lock = threading.Lock() + + async def send(self, message, target): + with self._lock: + if target not in self._pool: + self._pool[target] = queue.Queue() + self._pool[target].put(message) + + async def receive(self, target): + pass diff --git a/pyopenagi/agents/experiment/standard/config.json b/pyopenagi/agents/experiment/standard/config.json index 7b3fc3446..c062b9411 100644 --- a/pyopenagi/agents/experiment/standard/config.json +++ b/pyopenagi/agents/experiment/standard/config.json @@ -4,8 +4,6 @@ ], "tools": [ - "arxiv/arxiv", - "reader/file_reader" ], "meta": { "author": "example", diff --git a/pyopenagi/agents/experiment/standard/environment/code_environment.py b/pyopenagi/agents/experiment/standard/environment/code_environment.py index 7a6a09620..6f13d6421 100644 --- a/pyopenagi/agents/experiment/standard/environment/code_environment.py +++ b/pyopenagi/agents/experiment/standard/environment/code_environment.py @@ -26,7 +26,7 @@ def init_environment(self, requirement_list: List[str]): requirement_list (List[str]): The list of requirement commands(Format like `pip install numpy`). """ - if len(requirement_list) == 0: + if requirement_list is None: return for requirement in requirement_list: @@ -57,8 +57,9 @@ def step(self, code_block: str, language: str = "python"): str: The result of the code execution. """ # Create temp file, write python code into temp file, then execute it - with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=True) as temp_file: + with tempfile.NamedTemporaryFile(mode="w+", suffix=".py", delete=True) as temp_file: temp_file.write(code_block) + temp_file.flush() try: exec_res = subprocess.run( ["python", temp_file.name], diff --git a/pyopenagi/agents/experiment/standard/planning/planning_augmented.py b/pyopenagi/agents/experiment/standard/planning/memory_augmented.py similarity index 100% rename from pyopenagi/agents/experiment/standard/planning/planning_augmented.py rename to pyopenagi/agents/experiment/standard/planning/memory_augmented.py diff --git a/pyopenagi/agents/experiment/standard/planning/planning.py b/pyopenagi/agents/experiment/standard/planning/planning.py index bd9b7025e..2abc6729a 100644 --- a/pyopenagi/agents/experiment/standard/planning/planning.py +++ b/pyopenagi/agents/experiment/standard/planning/planning.py @@ -47,7 +47,8 @@ def __call__(self, messages: List, tools: List): } return result - if code_info := extract_code(response_message): + code_info = extract_code(response_message) + if not all(info is None for info in code_info): # action code result.action_type = "CODE" result.action_param = { diff --git a/pyopenagi/agents/experiment/standard/planning/reflexion.py b/pyopenagi/agents/experiment/standard/planning/reflexion.py new file mode 100644 index 000000000..e69de29bb diff --git a/pyopenagi/utils/chat_template.py b/pyopenagi/utils/chat_template.py index 3cd908543..df2550f82 100755 --- a/pyopenagi/utils/chat_template.py +++ b/pyopenagi/utils/chat_template.py @@ -2,14 +2,17 @@ from typing import List, Dict, Optional, Any, Union from typing_extensions import Literal # Import Literal from typing_extensions for stricter typing -class LLMQuery(BaseModel): +class Request(BaseModel): + pass + +class LLMQuery(Request): """ Query class represents the input structure for performing various actions. - + Attributes: messages (List[Dict[str, Union[str, Any]]]): A list of dictionaries where each dictionary represents a message containing 'role' and 'content' or other key-value pairs. - tools (Optional[List[Dict[str, Any]]]): An optional list of JSON-like objects (dictionaries) + tools (Optional[List[Dict[str, Any]]]): An optional list of JSON-like objects (dictionaries) representing tools and their parameters. Default is an empty list. action_type (Literal): A string that must be one of "message_llm", "call_tool", or "operate_file". This restricts the type of action the query performs. @@ -22,9 +25,9 @@ class LLMQuery(BaseModel): class Config: arbitrary_types_allowed = True # Allows the use of arbitrary types such as Any and Dict. - -class MemoryQuery(BaseModel): + +class MemoryQuery(Request): # messages: List[Dict[str, Union[str, Any]]] # List of message dictionaries, each containing role and content. # message_return_type: str = Field(default="text") # Type of the return message, default is "text". messages: List[Dict[str, Union[str, Any]]] @@ -32,27 +35,34 @@ class MemoryQuery(BaseModel): class Config: arbitrary_types_allowed = True # Allows the use of arbitrary types such as Any and Dict. - -class StorageQuery(BaseModel): + +class StorageQuery(Request): messages: List[Dict[str, Union[str, Any]]] # List of message dictionaries, each containing role and content. operation_type: str = Field(default="text") # Type of the return message, default is "text". class Config: arbitrary_types_allowed = True # Allows the use of arbitrary types such as Any and Dict. +class ToolQuery(Request): + tool_calls: List[Dict[str, Union[str, Any]]] # List of message dictionaries, each containing role and content. + + class Config: + arbitrary_types_allowed = True # Allows the use of arbitrary types such as Any and Dict. + class Response(BaseModel): """ Response class represents the output structure after performing actions. - + Attributes: response_message (Optional[str]): The generated response message. Default is None. - tool_calls (Optional[List[Dict[str, Any]]]): An optional list of JSON-like objects (dictionaries) + tool_calls (Optional[List[Dict[str, Any]]]): An optional list of JSON-like objects (dictionaries) representing the tool calls made during processing. Default is None. """ response_message: Optional[str] = None # The generated response message, default is None. tool_calls: Optional[List[Dict[str, Any]]] = None # List of JSON-like objects representing tool calls, default is None. + finished: bool class Config: arbitrary_types_allowed = True # Allows arbitrary types in validation. diff --git a/scripts/aios-interpreter/example_aios_interpreter.py b/scripts/aios-interpreter/example_aios_interpreter.py index 0a5487792..1ae7af1a5 100644 --- a/scripts/aios-interpreter/example_aios_interpreter.py +++ b/scripts/aios-interpreter/example_aios_interpreter.py @@ -3,7 +3,7 @@ from aios.sdk import FrameworkType from aios.sdk.adapter import prepare_framework -from aios.hooks.llm import aios_starter +from aios.hooks.starter import aios_starter from aios.utils.utils import ( parse_global_args, delete_directories diff --git a/scripts/aios-seeact/README.md b/scripts/aios-seeact/README.md index 3ff90d2d0..9c944c58a 100644 --- a/scripts/aios-seeact/README.md +++ b/scripts/aios-seeact/README.md @@ -64,7 +64,7 @@ DEFAULT_SETTINGS = { ``` ## Implementation Notes -- Uses GPT-4O for web interaction and visual understanding +- Uses GPT-4o for web interaction and visual understanding - Runs in headless mode by default - Uses Google as the default starting website - Automated web interaction capabilities diff --git a/scripts/aios-seeact/run_seeact.py b/scripts/aios-seeact/run_seeact.py index 6e87fd610..25e4275fd 100644 --- a/scripts/aios-seeact/run_seeact.py +++ b/scripts/aios-seeact/run_seeact.py @@ -1,17 +1,19 @@ #!/usr/bin/env python3 import os import sys -# Add AIOS path -aios_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')) -sys.path.insert(0, aios_root) +import warnings +import asyncio from aios.utils.utils import ( parse_global_args, delete_directories ) -import warnings -from aios.hooks.llm import aios_starter +from aios.hooks.starter import aios_starter from dotenv import load_dotenv -import asyncio + +# Add AIOS path +aios_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')) +sys.path.insert(0, aios_root) + def clean_cache(root_directory): targets = { @@ -22,6 +24,7 @@ def clean_cache(root_directory): } delete_directories(root_directory, targets) + def main(): main_id = os.getpid() print(f"Main ID is: {main_id}") @@ -67,5 +70,6 @@ def main(): clean_cache(root_directory="./") + if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/server.py b/server.py index 0a8b331d5..6481a37f8 100644 --- a/server.py +++ b/server.py @@ -1,6 +1,7 @@ from collections import OrderedDict from fastapi import Depends, FastAPI, Query from fastapi.middleware.cors import CORSMiddleware +from pydantic import BaseModel from aios.hooks.modules.scheduler import useFIFOScheduler from aios.hooks.modules.agent import useFactory @@ -15,6 +16,8 @@ from aios.core.schema import CoreSchema from aios.hooks.types.parser import ParserQuery +from aios.llm_cores.adapter import LLMAdapter + from aios.utils.utils import ( parse_global_args, ) @@ -29,6 +32,8 @@ import json +from pyopenagi.utils.chat_template import LLMQuery + load_dotenv() app = FastAPI() @@ -126,6 +131,21 @@ async def set_kernel(req: LLMParams): setLLMState(useCore(**req)) +class LLMCoreCallParams(BaseModel): + llm_name: str + query: LLMQuery + +@app.post("/call_llm_core") +async def call_llm_core(req: LLMCoreCallParams): + llm = LLMAdapter(req.llm_name) + core = llm.get_model() + + res = core.execute(req.query) + + return { + 'response': res + } + @app.post("/add_agent") async def add_agent( diff --git a/standard_main.py b/standard_main.py deleted file mode 100644 index 4aab0d7cb..000000000 --- a/standard_main.py +++ /dev/null @@ -1,30 +0,0 @@ -import os -from aios.hooks.llm import aios_starter -from aios.utils.utils import parse_global_args - - -def main(**kargs): - main_id = os.getpid() - print(f"Main ID is: {main_id}") - - with aios_starter(**kargs) as (submit_agent, await_agent_execution): - - agent_tasks = [ - ["experiment/standard", "Where is China?"] - ] - - agent_ids = [] - for agent_name, task_input in agent_tasks: - agent_id = submit_agent(agent_name=agent_name, task_input=task_input) - agent_ids.append(agent_id) - - for agent_id in agent_ids: - result = await_agent_execution(agent_id) - print(f"Agent_id: {agent_id} Result: {result}") - - -if __name__ == '__main__': - parser = parse_global_args() - args = parser.parse_args() - - main(**vars(args)) From 52ebda316e29e88c5d1e02c3d20ab377cf7b119c Mon Sep 17 00:00:00 2001 From: 2020-qqtcg Date: Wed, 20 Nov 2024 16:50:07 +0800 Subject: [PATCH 41/41] feat: code example --- .../experiment/standard/action/action.py | 4 ++ .../standard/communication/message_pool.py | 13 ++++-- scripts/aios-openagi/write_code.py | 42 +++++++++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 scripts/aios-openagi/write_code.py diff --git a/pyopenagi/agents/experiment/standard/action/action.py b/pyopenagi/agents/experiment/standard/action/action.py index 56b62c265..bf63aab0c 100644 --- a/pyopenagi/agents/experiment/standard/action/action.py +++ b/pyopenagi/agents/experiment/standard/action/action.py @@ -10,3 +10,7 @@ def __call__(self, *args, **kwargs): @abstractmethod def format_prompt(self): pass + + @staticmethod + def display(): + pass diff --git a/pyopenagi/agents/experiment/standard/communication/message_pool.py b/pyopenagi/agents/experiment/standard/communication/message_pool.py index 2de312eac..98e0bad1d 100644 --- a/pyopenagi/agents/experiment/standard/communication/message_pool.py +++ b/pyopenagi/agents/experiment/standard/communication/message_pool.py @@ -14,11 +14,18 @@ def __init__(self): super().__init__() self._lock = threading.Lock() - async def send(self, message, target): + async def send(self, message: Any, target: Any) -> None: with self._lock: if target not in self._pool: self._pool[target] = queue.Queue() self._pool[target].put(message) - async def receive(self, target): - pass + async def receive(self, target: Any) -> Any: + if target not in self._pool: + yield None + + with self._lock: + if target in self._pool: + queue = self._pool[target] + while not queue.empty(): + yield queue.get() diff --git a/scripts/aios-openagi/write_code.py b/scripts/aios-openagi/write_code.py new file mode 100644 index 000000000..ad9f1c0c3 --- /dev/null +++ b/scripts/aios-openagi/write_code.py @@ -0,0 +1,42 @@ +import os +import warnings + +from dotenv import load_dotenv + +from aios.hooks.starter import aios_starter +from aios.utils.utils import parse_global_args +from pyopenagi.agents.experiment.standard.agent import StandardAgent + + +class StandardAgentImpl(StandardAgent): + + def custom_prompt(self) -> str: + return "If you think task is finished, output TERMINATE." + + def custom_terminate(self) -> bool: + return True if "TERMINATE" in self.short_term_memory.last_message()["content"] else False + + +def main(): + main_id = os.getpid() + print(f"Main ID is: {main_id}") + warnings.filterwarnings("ignore") + parser = parse_global_args() + args = parser.parse_args() + load_dotenv() + + with aios_starter(**vars(args)): + agent = StandardAgentImpl( + agent_name="Agent", + task_input="Write code to solve following problem: In a group of 23 people, the probability of at least " + "two having the same birthday is greater" + "than 50%" + ) + + result = agent.run() + print(f"Result: {result}") + + +# python -m scripts.aios-openagi.write_code --llm_name gpt-4o-mini +if __name__ == '__main__': + main()