diff --git a/src/rawdog/parsing.py b/src/rawdog/parsing.py index 0bbc00f..860a3db 100644 --- a/src/rawdog/parsing.py +++ b/src/rawdog/parsing.py @@ -1,29 +1,41 @@ import ast import json +import re def parse_script(response: str) -> tuple[str, str]: - """Split the response into a message and a script. + """Split the response into a message and a script, handling variations of 'python' prefix and JSON content. - Expected use is: run the script if there is one, otherwise print the message. + Args: + response (str): The input response containing a message and optionally a script. + + Returns: + tuple[str, str]: A tuple containing the message (or error message) and the script, if valid. """ - # Parse delimiter - n_delimiters = response.count("```") - if n_delimiters < 2: - return response, "" - segments = response.split("```") - message = f"{segments[0]}\n{segments[-1]}" - script = "```".join(segments[1:-1]).strip() # Leave 'inner' delimiters alone + try: + # Extract message and script using split on triple backticks + parts = response.split('```') + if len(parts) < 3: + return response, "" # Not enough parts, return original message and empty script + + # Clean and identify parts + message = parts[0] + parts[-1] # Consider the first and last parts as the message + script = '```'.join(parts[1:-1]).strip() # Join any inner parts as the script + + # Remove 'python' or similar prefixes from the script + script = re.sub(r"^\s*python[0-9]*\s*", "", script, flags=re.IGNORECASE) + + # Attempt to interpret script as JSON, revert if it fails + try: + parsed_script = json.loads(script) + script = json.dumps(parsed_script) # Convert back to string to validate as Python code + except json.JSONDecodeError: + pass # Keep script as is if not JSON - # Check for common mistakes - if script.split("\n")[0].startswith("python"): - script = "\n".join(script.split("\n")[1:]) - try: # Make sure it isn't json - script = json.loads(script) - except Exception: - pass - try: # Make sure it's valid python + # Validate as Python code ast.parse(script) - except SyntaxError: - return f"Script contains invalid Python:\n{response}", "" - return message, script + return message, script + except SyntaxError as e: + return f"Error in Python syntax: {e}", "" + except Exception as e: + return f"Unhandled error: {e}", ""