From e6ee4d4796bbfcd93c8fcace9402356c84181771 Mon Sep 17 00:00:00 2001 From: Rushi-24 <2021.yeole.rushikesh@ves.ac.in> Date: Wed, 1 Oct 2025 13:55:11 +0530 Subject: [PATCH] Providing proper step logs #40 Providing proper step logs in the Microbot and openAi_api file --- src/microbots/MicroBot.py | 61 ++++++++++++++++++++++++++++++--- src/microbots/llm/openai_api.py | 13 ++++--- 2 files changed, 64 insertions(+), 10 deletions(-) diff --git a/src/microbots/MicroBot.py b/src/microbots/MicroBot.py index 708787c..83f71eb 100644 --- a/src/microbots/MicroBot.py +++ b/src/microbots/MicroBot.py @@ -23,16 +23,19 @@ { task_done: true | false, command: " | null", - result: str | null + result: str | null, + reasoning: "Brief explanation of what you're thinking and why you're running this command" } ``` """ system_prompt_common = """There is a shell session open for you. I will provide a task to achieve using the shell. - You will provide the commands to achieve the task in this particular below json format, Ensure all the time to respond in this format only and nothing else, also all the properties ( task_done, command, result ) are mandatory on each response + You will provide the commands to achieve the task in this particular below json format, Ensure all the time to respond in this format only and nothing else, also all the properties ( task_done, command, result, reasoning ) are mandatory on each response {llm_output_format} after each command I will provide the output of the command. + + IMPORTANT: Always include 'reasoning' field to explain your thought process before executing each command. ensure to run only one command at a time. I won't be able to intervene once I have given task. .""" @@ -105,9 +108,28 @@ def run(self, task, max_iterations=20, timeout_in_seconds=200) -> BotRunResult: result=None, error="Did not complete", ) - logger.info("%s TASK STARTED : %s...", LogLevelEmoji.INFO, task[0:15]) + print(f"\n{'='*80}") + print(f"šŸš€ TASK STARTED: {task}") + print(f"{'='*80}") + + logger.info("%s TASK STARTED : %s...", LogLevelEmoji.INFO, task[0:50]) while llm_response.task_done is False: + print(f"\n{'─'*80}") + print(f"šŸ”„ STEP {iteration_count}") + print(f"{'─'*80}") + + # Show LLM's thought process + print(f"\nšŸ’­ LLM ANALYSIS:") + if hasattr(llm_response, 'reasoning') and llm_response.reasoning: + print(f" {llm_response.reasoning}") + else: + print(f" Analyzing current situation and determining next action...") + + # Show the command to execute + print(f"\n⚔ COMMAND TO EXECUTE:") + print(f" {LogTextColor.OKBLUE}{llm_response.command}{LogTextColor.ENDC}") + logger.info("%s Step-%d %s", "-" * 20, iteration_count, "-" * 20) logger.info( f" āž”ļø LLM tool call : {LogTextColor.OKBLUE}{json.dumps(llm_response.command)}{LogTextColor.ENDC}", @@ -132,11 +154,27 @@ def run(self, task, max_iterations=20, timeout_in_seconds=200) -> BotRunResult: return return_value llm_command_output = self.environment.execute(llm_response.command) + + # Show command output clearly + print(f"\nšŸ“¤ COMMAND OUTPUT:") if llm_command_output.stdout: + print(f" āœ… STDOUT:") + for line in llm_command_output.stdout.split('\n'): + if line.strip(): + print(f" {line}") logger.info( " ā¬…ļø Command Execution Output: %s", llm_command_output.stdout, ) + + if llm_command_output.stderr: + print(f" āŒ STDERR:") + for line in llm_command_output.stderr.split('\n'): + if line.strip(): + print(f" {line}") + + if not llm_command_output.stdout and not llm_command_output.stderr: + print(f" ā„¹ļø No output received") # Convert CmdReturn to string for LLM if llm_command_output.stdout: @@ -146,9 +184,22 @@ def run(self, task, max_iterations=20, timeout_in_seconds=200) -> BotRunResult: else: output_text = "No output received" + print(f"\nšŸ”„ SENDING OUTPUT TO LLM...") llm_response = self.llm.ask(output_text) - logger.info("šŸ”š TASK COMPLETED : %s...", task[0:15]) + print(f"\n{'='*80}") + print(f"āœ… TASK COMPLETED!") + print(f"{'='*80}") + print(f"\nšŸŽÆ FINAL RESULT:") + if llm_response.result: + for line in str(llm_response.result).split('\n'): + if line.strip(): + print(f" {line}") + else: + print(" Task completed successfully") + print(f"\n{'='*80}") + + logger.info("šŸ”š TASK COMPLETED : %s...", task[0:50]) return BotRunResult(status=True, result=llm_response.result, error=None) # TODO : pass the sandbox path @@ -167,7 +218,7 @@ def _create_environment(self, folder_to_mount: Optional[Mount]): ) def _create_llm(self): - if self.model_provider == ModelProvider.OPENAI: + if self.model_provider in [ModelProvider.OPENAI, ModelProvider.OPENAI_STANDARD]: self.llm = OpenAIApi( system_prompt=self.system_prompt, deployment_name=self.deployment_name ) diff --git a/src/microbots/llm/openai_api.py b/src/microbots/llm/openai_api.py index 7367819..9bc6b31 100644 --- a/src/microbots/llm/openai_api.py +++ b/src/microbots/llm/openai_api.py @@ -24,6 +24,7 @@ class llmAskResponse: task_done: bool = False command: str = "" result: str | None = None + reasoning: str | None = None class OpenAIApi: @@ -38,12 +39,12 @@ def ask(self, message) -> llmAskResponse: self.messages.append({"role": "user", "content": message}) return_value = {} while self._validate_llm_response(return_value) is False: - response = self.ai_client.responses.create( + response = self.ai_client.chat.completions.create( model=self.deployment_name, - input=self.messages, + messages=self.messages, ) try: - return_value = json.loads(response.output_text) + return_value = json.loads(response.choices[0].message.content) except Exception as e: logger.error( f"%s Error occurred while dumping JSON: {e}", LogLevelEmoji.ERROR @@ -52,7 +53,7 @@ def ask(self, message) -> llmAskResponse: "%s Failed to parse JSON from LLM response and the response is", LogLevelEmoji.ERROR, ) - logger.error(response.output_text) + logger.error(response.choices[0].message.content) self.messages.append({"role": "assistant", "content": json.dumps(return_value)}) @@ -60,6 +61,7 @@ def ask(self, message) -> llmAskResponse: task_done=return_value["task_done"], result=return_value["result"], command=return_value["command"], + reasoning=return_value.get("reasoning", "No reasoning provided"), ) def clear_history(self): @@ -72,7 +74,8 @@ def clear_history(self): return True def _validate_llm_response(self, response: dict) -> bool: - if "task_done" in response and "command" in response and "result" in response: + required_fields = ["task_done", "command", "result"] + if all(field in response for field in required_fields): logger.info("The llm response is %s ", response) return True return False