From 2dc1fc39b3e3082c39ae5dc928c915e8a4889340 Mon Sep 17 00:00:00 2001 From: Alex Korbonits Date: Sun, 12 Apr 2026 23:36:19 -0700 Subject: [PATCH] Add Ruff linting, pre-commit hooks, and CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add [tool.ruff] config to pyproject.toml (E/F/I rules, line-length 120) - Add .pre-commit-config.yaml with ruff + ruff-format hooks - Add .github/workflows/lint.yml CI job via uv - Fix E101: mixed tabs/spaces in computer_use/games/tetris/workers.py Auto-fixed 276 import-sort and style violations. Remaining notes (suppressed in config): - F821: undefined names 'e' in sokoban_agent.py:578 (bare except without 'as e' binding), 'model_name_arg' in single_agent_runner.py:408,426, and 'token_limit' in tools/serving/api_manager.py:1128 — all potential NameErrors at runtime - F811: estimate_token_count redefined in tools/serving/api_providers.py:29 (import on line 19 overwritten by function definition on line 29) - E712: 19 equality comparisons to True/False across multiple files --- .github/workflows/lint.yml | 17 +++++ .pre-commit-config.yaml | 7 ++ computer_use/games/ace_attorney/ace_agent.py | 47 +++++-------- computer_use/games/ace_attorney/workers.py | 27 +++++--- computer_use/games/candy/candy_agent.py | 10 +-- computer_use/games/candy/workers.py | 25 ++++--- computer_use/games/game_2048/2048_agent.py | 14 ++-- computer_use/games/game_2048/game.py | 5 +- computer_use/games/game_2048/game_logic.py | 6 +- computer_use/games/game_2048/workers.py | 14 ++-- .../end_to_end_sokoban/sokoban_agent.py | 30 +++++---- .../sokoban/end_to_end_sokoban/sokoban_env.py | 14 ++-- computer_use/games/sokoban/sokoban.py | 10 +-- computer_use/games/sokoban/sokoban_agent.py | 17 ++--- computer_use/games/sokoban/workers.py | 20 ++++-- computer_use/games/superMario/mario_agent.py | 7 +- computer_use/games/superMario/workers.py | 14 ++-- .../tetris/Python-Tetris-Game-Pygame/block.py | 3 +- .../Python-Tetris-Game-Pygame/blocks.py | 1 + .../tetris/Python-Tetris-Game-Pygame/game.py | 6 +- .../tetris/Python-Tetris-Game-Pygame/grid.py | 1 + .../tetris/Python-Tetris-Game-Pygame/main.py | 12 ++-- computer_use/games/tetris/speculators.py | 19 ++++-- computer_use/games/tetris/tetris_agent.py | 7 +- computer_use/games/tetris/workers.py | 45 ++++++++----- eval/notebook_utils.py | 49 ++++++-------- eval/replay_utils.py | 17 ++--- eval/video_generation_script.py | 14 ++-- gamingagent/agents/base_agent.py | 16 ++--- gamingagent/envs/__init__.py | 4 +- .../custom_01_2048/twentyFortyEightEnv.py | 7 +- .../envs/custom_02_sokoban/sokobanEnv.py | 16 ++--- .../custom_03_candy_crush/candyCrushEnv.py | 22 +++--- .../tile_match_gym/board.py | 6 +- .../tile_match_gym/tile_match_env.py | 12 ++-- .../tile_match_gym/utils/utils.py | 7 +- .../tile_match_gym/wrappers.py | 6 +- .../envs/custom_04_tetris/tetrisEnv.py | 25 ++++--- gamingagent/envs/custom_05_doom/doomEnv.py | 19 +++--- .../full_collision_map.py | 5 +- .../custom_06_pokemon_red/pokemonRedEnv.py | 22 +++--- gamingagent/envs/env_utils.py | 7 +- gamingagent/envs/gym_env_adapter.py | 10 +-- .../superMarioBrosEnv.py | 13 ++-- .../retro_02_ace_attorney/aceAttorneyEnv.py | 28 ++++---- .../envs/retro_02_ace_attorney/test.py | 21 +++--- .../retro_03_1942/NineteenFortyTwo_env.py | 12 ++-- .../envs/zoo_01_tictactoe/TicTacToeEnv.py | 6 +- .../envs/zoo_02_texasholdem/TexasHoldemEnv.py | 10 +-- gamingagent/modules/__init__.py | 2 +- gamingagent/modules/base_module.py | 11 ++- gamingagent/modules/core_module.py | 11 +-- gamingagent/modules/memory_module.py | 13 ++-- gamingagent/modules/perception_module.py | 13 ++-- gamingagent/modules/prompt_graph.py | 6 +- gamingagent/modules/reasoning_module.py | 7 +- lmgame-bench/multi_agent_runner.py | 24 +++---- lmgame-bench/run.py | 8 +-- lmgame-bench/single_agent_runner.py | 25 +++---- pyproject.toml | 11 +++ tests/pokemon_red_test/test_game_env.py | 5 +- tests/test_agents/modules/doom_base_module.py | 7 +- tests/test_run.py | 10 +-- tools/modal/serve_instance.py | 4 +- tools/modal/serve_instance_qwen.py | 4 +- tools/prompt_opt_dspy.py | 4 +- tools/serving/api_cost_calculator.py | 19 +++--- tools/serving/api_manager.py | 67 +++++++++---------- tools/serving/api_providers.py | 29 +++----- tools/serving/constants.py | 7 +- tools/utils.py | 4 +- 71 files changed, 533 insertions(+), 490 deletions(-) create mode 100644 .github/workflows/lint.yml create mode 100644 .pre-commit-config.yaml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 00000000..fe58f73b --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,17 @@ +name: Lint + +on: + push: + branches: [main] + pull_request: + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/setup-uv@v5 + - run: uv python install 3.10 + - run: uv pip install ruff + - run: uv run ruff check . + - run: uv run ruff format --check . diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..700cbc40 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,7 @@ +repos: + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.12.2 + hooks: + - id: ruff + args: [--fix] + - id: ruff-format diff --git a/computer_use/games/ace_attorney/ace_agent.py b/computer_use/games/ace_attorney/ace_agent.py index 79b0fecd..80824fc7 100644 --- a/computer_use/games/ace_attorney/ace_agent.py +++ b/computer_use/games/ace_attorney/ace_agent.py @@ -1,35 +1,24 @@ -import time -import numpy as np -import concurrent.futures import argparse -from collections import deque, Counter -import shutil -import threading -from concurrent.futures import ThreadPoolExecutor +import concurrent.futures import datetime - import os -import json -import re -import pyautogui -# from games.ace_attorney.reflection_worker import ReflectionTracker - +import time +from collections import Counter +# from games.ace_attorney.reflection_worker import ReflectionTracker from games.ace_attorney.workers import ( - ace_attorney_worker, - perform_move, - ace_evidence_worker, - short_term_memory_worker, - vision_only_reasoning_worker, - long_term_memory_worker, - memory_retrieval_worker, - vision_only_ace_attorney_worker, + ace_attorney_worker, + ace_evidence_worker, check_end_statement, check_skip_conversation, - handle_skip_conversation + handle_skip_conversation, + long_term_memory_worker, + perform_move, + short_term_memory_worker, + vision_only_ace_attorney_worker, ) -from tools.utils import str2bool, encode_image, log_output, get_annotate_img, capture_game_window, log_game_event -from collections import Counter + +from tools.utils import log_game_event, str2bool # Global base cache directory BASE_CACHE_DIR = "cache/ace_attorney" @@ -184,7 +173,7 @@ def main(): print(f"\nThread {i} Analysis:") print(f"├── Game State: {result['game_state']}") print(f"├── Move: {result['move'].strip().lower()}") - print(f"├── Thought Process:") + print("├── Thought Process:") print(f"│ ├── Primary Reasoning: {result['thought']}") if "dialog" in result: if isinstance(result['dialog'], dict) and 'name' in result['dialog'] and 'text' in result['dialog']: @@ -228,7 +217,7 @@ def main(): print(f"│ ├── Votes: {count}") # Find all thoughts associated with this move move_indices = [i for i, m in enumerate(moves) if m == move] - print(f"│ ├── Supporting Thoughts:") + print("│ ├── Supporting Thoughts:") for idx in move_indices: print(f"│ │ ├── Thought: {thoughts[idx]}") if dialogs[idx]: @@ -253,7 +242,7 @@ def main(): print("\n=== Final Decision ===") print(f"├── Game State: {chosen_game_state}") print(f"├── Chosen Move: {chosen_move}") - print(f"├── Decision Reasoning:") + print("├── Decision Reasoning:") print(f"│ ├── Primary Thought: {chosen_thought}") if chosen_dialog: if isinstance(chosen_dialog, dict) and 'name' in chosen_dialog and 'text' in chosen_dialog: @@ -263,7 +252,7 @@ def main(): if chosen_evidence: print(f"│ ├── Evidence Context: {chosen_evidence['name']}: {chosen_evidence['description']}") print(f"│ └── Scene Context: {chosen_scene[:200]}...") - print(f"└── Execution Status: Pending") + print("└── Execution Status: Pending") print("="*70 + "\n") # Log the final decision @@ -334,7 +323,7 @@ def main(): ) dialog_new = { "name": "Phoenix", - "text": f"I revceive a new evidence 'Mia's Memo'." + "text": "I revceive a new evidence 'Mia's Memo'." } long_term_memory_worker( system_prompt, diff --git a/computer_use/games/ace_attorney/workers.py b/computer_use/games/ace_attorney/workers.py index 1c74d973..d8897bb1 100644 --- a/computer_use/games/ace_attorney/workers.py +++ b/computer_use/games/ace_attorney/workers.py @@ -1,13 +1,22 @@ -import time +import json import os -import pyautogui -import numpy as np +import re +import time -from tools.utils import encode_image, log_output, get_annotate_img, capture_game_window, log_request_cost -from tools.serving.api_providers import anthropic_completion, anthropic_text_completion, openai_completion, openai_text_reasoning_completion, gemini_completion, gemini_text_completion, deepseek_text_reasoning_completion, together_ai_completion +import pyautogui from tools.api_cost_calculator import calculate_all_costs_and_tokens, convert_string_to_messsage -import re -import json + +from tools.serving.api_providers import ( + anthropic_completion, + anthropic_text_completion, + deepseek_text_reasoning_completion, + gemini_completion, + gemini_text_completion, + openai_completion, + openai_text_reasoning_completion, + together_ai_completion, +) +from tools.utils import capture_game_window, encode_image, log_request_cost # Default cache directory (can be overridden by passing cache_dir parameter) DEFAULT_CACHE_DIR = "cache/ace_attorney" @@ -966,7 +975,7 @@ def check_skip_conversation(dialog, episode_name): # Check if dialog matches any key in the skip conversations episode_convs = skip_conversations.get(episode_name, {}) if dialog_entry in episode_convs: - print(f">>> MATCH FOUND! Dialog matches key in skip conversations") + print(">>> MATCH FOUND! Dialog matches key in skip conversations") return episode_convs[dialog_entry] print("No matching key found in skip conversations") @@ -995,7 +1004,7 @@ def handle_skip_conversation(system_prompt, api_provider, model_name, prev_respo print("=== Starting Skip Conversation ===") print(f"├── Episode: {episode_name}") print(f"├── Number of dialogs to skip: {len(skip_dialogs) - 1}") - print(f"└── Dialog sequence:") + print("└── Dialog sequence:") for i, skip_dialog in enumerate(skip_dialogs): print(f" {i+1}. {skip_dialog}") print("="*70 + "\n") diff --git a/computer_use/games/candy/candy_agent.py b/computer_use/games/candy/candy_agent.py index 1fab106e..42031b90 100644 --- a/computer_use/games/candy/candy_agent.py +++ b/computer_use/games/candy/candy_agent.py @@ -1,13 +1,13 @@ -import time -import numpy as np -import concurrent.futures import argparse +import os +import shutil +import time from collections import deque from games.candy.workers import candy_crush_worker + from tools.utils import str2bool -import os -import shutil + # System prompt remains constant system_prompt = ( "You are a highly intelligent Candy Crush gameplay agent trained to achieve the highest possible score " diff --git a/computer_use/games/candy/workers.py b/computer_use/games/candy/workers.py index 630211be..0d43ac57 100644 --- a/computer_use/games/candy/workers.py +++ b/computer_use/games/candy/workers.py @@ -1,22 +1,25 @@ -import time import os +import time + import pyautogui -import numpy as np -from tools.utils import encode_image, log_output, extract_python_code, get_annotate_img -from tools.serving.api_providers import anthropic_completion, openai_completion, gemini_completion, anthropic_text_completion, gemini_text_completion, openai_text_reasoning_completion, openai_vision_reasoning_completion, deepseek_text_reasoning_completion +from tools.serving.api_providers import ( + anthropic_completion, + anthropic_text_completion, + deepseek_text_reasoning_completion, + gemini_completion, + gemini_text_completion, + openai_completion, + openai_text_reasoning_completion, + openai_vision_reasoning_completion, +) +from tools.utils import encode_image, get_annotate_img, log_output cache_dir = "cache/candy_crush" -import time -import os -import pyautogui -import numpy as np -from tools.utils import encode_image, log_output, extract_python_code, get_annotate_img -from tools.serving.api_providers import anthropic_completion, openai_completion, gemini_completion -import re import json +import re CACHE_DIR = "cache/candy_crush" diff --git a/computer_use/games/game_2048/2048_agent.py b/computer_use/games/game_2048/2048_agent.py index cd74aa1c..041c473a 100644 --- a/computer_use/games/game_2048/2048_agent.py +++ b/computer_use/games/game_2048/2048_agent.py @@ -1,18 +1,14 @@ -import time -import numpy as np -import concurrent.futures import argparse -from collections import deque, Counter +import concurrent.futures import datetime - import os -import json -import re -import pyautogui +import time +from collections import Counter, deque +import pyautogui from games.game_2048.workers import game_2048_worker + from tools.utils import str2bool -from collections import Counter CACHE_DIR = "cache/2048" os.makedirs(CACHE_DIR, exist_ok=True) diff --git a/computer_use/games/game_2048/game.py b/computer_use/games/game_2048/game.py index 113b1524..dfbf532e 100644 --- a/computer_use/games/game_2048/game.py +++ b/computer_use/games/game_2048/game.py @@ -1,13 +1,12 @@ import json +import os import sys import time from copy import deepcopy import pygame -from pygame.locals import * - from logic import * -import os +from pygame.locals import * # TODO: Add a RULES button on start page # TODO: Add score keeping diff --git a/computer_use/games/game_2048/game_logic.py b/computer_use/games/game_2048/game_logic.py index 7873f19f..d0ecb2b4 100644 --- a/computer_use/games/game_2048/game_logic.py +++ b/computer_use/games/game_2048/game_logic.py @@ -1,8 +1,8 @@ -import json -import sys import argparse -import pygame +import json import os + +import pygame from game import playGame # Default window size diff --git a/computer_use/games/game_2048/workers.py b/computer_use/games/game_2048/workers.py index 714f7213..3e461f66 100644 --- a/computer_use/games/game_2048/workers.py +++ b/computer_use/games/game_2048/workers.py @@ -1,14 +1,14 @@ -import time -import os -import pyautogui -import numpy as np import datetime +import json +import os +import re import shutil +import time + +import pyautogui -from tools.utils import encode_image, log_output, get_annotate_img from tools.serving.api_manager import APIManager -import re -import json +from tools.utils import get_annotate_img, log_output CACHE_DIR = "cache/2048" diff --git a/computer_use/games/sokoban/end_to_end_sokoban/sokoban_agent.py b/computer_use/games/sokoban/end_to_end_sokoban/sokoban_agent.py index 064fd73d..445a6046 100644 --- a/computer_use/games/sokoban/end_to_end_sokoban/sokoban_agent.py +++ b/computer_use/games/sokoban/end_to_end_sokoban/sokoban_agent.py @@ -1,26 +1,28 @@ # filename: gamingagent/agents/sokoban_agent.py -import numpy as np -import time +import argparse # Added for command-line arguments +import base64 +import io import os import re -import json import sys -from collections import deque # Added for MemoryModule +import time +import traceback +from collections import deque # Added for MemoryModule + from gamingagent.envs.sokoban_env import CustomSokobanEnv +from PIL import Image + from tools.serving.api_providers import ( - anthropic_completion, anthropic_text_completion, - openai_completion, openai_text_reasoning_completion, - gemini_completion, gemini_text_completion, + anthropic_completion, + anthropic_text_completion, deepseek_text_reasoning_completion, + gemini_completion, + gemini_text_completion, + openai_completion, + openai_text_reasoning_completion, together_ai_completion, - xai_grok_completion + xai_grok_completion, ) -from gamingagent.utils.utils import convert_to_json_serializable # Added for JSONL logging -import argparse # Added for command-line arguments -import io -import base64 -from PIL import Image -import traceback CACHE_DIR = "cache/sokoban" os.makedirs(CACHE_DIR, exist_ok=True) diff --git a/computer_use/games/sokoban/end_to_end_sokoban/sokoban_env.py b/computer_use/games/sokoban/end_to_end_sokoban/sokoban_env.py index de8bb865..03f12cda 100644 --- a/computer_use/games/sokoban/end_to_end_sokoban/sokoban_env.py +++ b/computer_use/games/sokoban/end_to_end_sokoban/sokoban_env.py @@ -2,8 +2,9 @@ #!/usr/bin/env python # --- Add local gym-sokoban to path --- -import sys import os +import sys + # Get the directory containing this file (envs/) envs_dir = os.path.dirname(os.path.abspath(__file__)) # Go up one level to gamingagent/ @@ -24,11 +25,12 @@ # Now the regular imports start import gymnasium as gym + # Try importing gym_sokoban, handle potential import error try: - import gym_sokoban - from gym_sokoban.envs.sokoban_env import SokobanEnv, ACTION_LOOKUP, CHANGE_COORDINATES + import gym_sokoban # noqa: F401 from gym_sokoban.envs.render_utils import room_to_rgb + from gym_sokoban.envs.sokoban_env import ACTION_LOOKUP, CHANGE_COORDINATES, SokobanEnv except ImportError: print("Warning: gym_sokoban not found. Please install it: pip install gym-sokoban") # Define dummy classes/variables if needed for type hinting or basic structure @@ -39,10 +41,10 @@ class SokobanEnv(gym.Env): pass CHANGE_COORDINATES = {} def room_to_rgb(room_state, room_fixed): return None -import numpy as np import sys -import pygame # For render mode check -import json # Added missing import for potential future use loading dims/levels + +import numpy as np +import pygame # For render mode check # Mapping from your level file characters to gym-sokoban internal state codes. # See gym_sokoban.envs.room_utils for original code definitions: diff --git a/computer_use/games/sokoban/sokoban.py b/computer_use/games/sokoban/sokoban.py index 33b4b759..87f3c30f 100755 --- a/computer_use/games/sokoban/sokoban.py +++ b/computer_use/games/sokoban/sokoban.py @@ -1,12 +1,12 @@ #!../bin/python -import sys -import pygame -import string -import queue +import copy import json import os -import copy +import queue +import sys + +import pygame CACHE_DIR = "cache/sokoban" diff --git a/computer_use/games/sokoban/sokoban_agent.py b/computer_use/games/sokoban/sokoban_agent.py index 71ec2f3b..6d6e634f 100644 --- a/computer_use/games/sokoban/sokoban_agent.py +++ b/computer_use/games/sokoban/sokoban_agent.py @@ -1,20 +1,17 @@ -import time -import numpy as np -import concurrent.futures import argparse -from collections import deque, Counter - -import os +import concurrent.futures import json -import re -import pyautogui -from tools.utils import str2bool +import os +import time +from collections import Counter, deque +import pyautogui from games.sokoban.workers import sokoban_worker +from tools.utils import str2bool + CACHE_DIR = "cache/sokoban" -from collections import Counter def majority_vote_move(moves_list, prev_move=None): """ diff --git a/computer_use/games/sokoban/workers.py b/computer_use/games/sokoban/workers.py index 27755f92..e27eb835 100644 --- a/computer_use/games/sokoban/workers.py +++ b/computer_use/games/sokoban/workers.py @@ -1,12 +1,18 @@ -import time +import json import os -import pyautogui -import numpy as np - -from tools.utils import encode_image, log_output, get_annotate_img -from tools.serving.api_providers import anthropic_completion, anthropic_text_completion, openai_completion, openai_text_reasoning_completion, gemini_completion, gemini_text_completion, deepseek_text_reasoning_completion import re -import json +import time + +from tools.serving.api_providers import ( + anthropic_completion, + anthropic_text_completion, + deepseek_text_reasoning_completion, + gemini_completion, + gemini_text_completion, + openai_completion, + openai_text_reasoning_completion, +) +from tools.utils import encode_image, get_annotate_img, log_output CACHE_DIR = "cache/sokoban" diff --git a/computer_use/games/superMario/mario_agent.py b/computer_use/games/superMario/mario_agent.py index cbf161a3..bc54af6a 100644 --- a/computer_use/games/superMario/mario_agent.py +++ b/computer_use/games/superMario/mario_agent.py @@ -1,9 +1,8 @@ -import time -import numpy as np -import concurrent.futures import argparse +import concurrent.futures +import time -from games.superMario.workers import worker_short, worker_long +from games.superMario.workers import worker_long, worker_short # System prompt remains constant system_prompt = ( diff --git a/computer_use/games/superMario/workers.py b/computer_use/games/superMario/workers.py index 919def87..4db4a974 100644 --- a/computer_use/games/superMario/workers.py +++ b/computer_use/games/superMario/workers.py @@ -1,10 +1,12 @@ -import time import os -import pyautogui +import time + import numpy as np +import pyautogui + +from tools.serving.api_providers import anthropic_completion, gemini_completion, openai_completion +from tools.utils import encode_image, extract_python_code, log_output -from tools.utils import encode_image, log_output, extract_python_code -from tools.serving.api_providers import anthropic_completion, openai_completion, gemini_completion def worker_short(thread_id, offset, system_prompt, api_provider, model_name): """ @@ -18,7 +20,7 @@ def worker_short(thread_id, offset, system_prompt, api_provider, model_name): print(f"[Thread {thread_id} - SHORT] Starting after {offset}s delay...") short_prompt = ( - f"Analyze the current game state and generate PyAutoGUI code to control Mario " + "Analyze the current game state and generate PyAutoGUI code to control Mario " "for the next 1 second.\n" "Mario's position most likely has moved forward when the generated code gets to execute.\n" "Your objective is to avoid obstacles, enemies, and hazards.\n" @@ -101,7 +103,7 @@ def worker_long(thread_id, offset, system_prompt, api_provider, model_name): print(f"[Thread {thread_id} - LONG] Starting after {offset}s delay...") long_prompt = ( - f"Analyze the current game state and generate PyAutoGUI code to control Mario " + "Analyze the current game state and generate PyAutoGUI code to control Mario " "for the next 2 seconds.\n" "Mario's position most likely has moved forward when the generated code gets to execute.\n" "Your objective is to make progress while avoiding obstacles, enemies, and hazards.\n" diff --git a/computer_use/games/tetris/Python-Tetris-Game-Pygame/block.py b/computer_use/games/tetris/Python-Tetris-Game-Pygame/block.py index e9882733..8fb6afc5 100644 --- a/computer_use/games/tetris/Python-Tetris-Game-Pygame/block.py +++ b/computer_use/games/tetris/Python-Tetris-Game-Pygame/block.py @@ -1,7 +1,8 @@ -from colors import Colors import pygame +from colors import Colors from position import Position + class Block: def __init__(self, id): self.id = id diff --git a/computer_use/games/tetris/Python-Tetris-Game-Pygame/blocks.py b/computer_use/games/tetris/Python-Tetris-Game-Pygame/blocks.py index e039030f..2a8502f5 100644 --- a/computer_use/games/tetris/Python-Tetris-Game-Pygame/blocks.py +++ b/computer_use/games/tetris/Python-Tetris-Game-Pygame/blocks.py @@ -1,6 +1,7 @@ from block import Block from position import Position + class LBlock(Block): def __init__(self): super().__init__(id = 1) diff --git a/computer_use/games/tetris/Python-Tetris-Game-Pygame/game.py b/computer_use/games/tetris/Python-Tetris-Game-Pygame/game.py index a610a73f..ace5d818 100644 --- a/computer_use/games/tetris/Python-Tetris-Game-Pygame/game.py +++ b/computer_use/games/tetris/Python-Tetris-Game-Pygame/game.py @@ -1,7 +1,9 @@ -from grid import Grid -from blocks import * import random + import pygame +from blocks import * +from grid import Grid + class Game: def __init__(self): diff --git a/computer_use/games/tetris/Python-Tetris-Game-Pygame/grid.py b/computer_use/games/tetris/Python-Tetris-Game-Pygame/grid.py index 7b146b9d..eae602fc 100644 --- a/computer_use/games/tetris/Python-Tetris-Game-Pygame/grid.py +++ b/computer_use/games/tetris/Python-Tetris-Game-Pygame/grid.py @@ -1,6 +1,7 @@ import pygame from colors import Colors + class Grid: def __init__(self): self.num_rows = 20 diff --git a/computer_use/games/tetris/Python-Tetris-Game-Pygame/main.py b/computer_use/games/tetris/Python-Tetris-Game-Pygame/main.py index 1c42b570..2f707b61 100644 --- a/computer_use/games/tetris/Python-Tetris-Game-Pygame/main.py +++ b/computer_use/games/tetris/Python-Tetris-Game-Pygame/main.py @@ -1,10 +1,10 @@ -import pygame +import json +import os import sys -from game import Game -from colors import Colors -import os -import json +import pygame +from colors import Colors +from game import Game pygame.init() @@ -25,7 +25,7 @@ GAME_UPDATE = pygame.USEREVENT pygame.time.set_timer(GAME_UPDATE, 1200) # 2800 for vision-text -CACHE_DIR = f"cache/tetris" +CACHE_DIR = "cache/tetris" # save state os.makedirs(CACHE_DIR, exist_ok=True) diff --git a/computer_use/games/tetris/speculators.py b/computer_use/games/tetris/speculators.py index 290c0503..6cdb781d 100644 --- a/computer_use/games/tetris/speculators.py +++ b/computer_use/games/tetris/speculators.py @@ -1,10 +1,21 @@ -import time import os -import pyautogui +import time + import numpy as np -from tools.utils import encode_image, log_output, extract_python_code, build_iteration_content, find_iteration_dirs, extract_planning_prompt, read_log_to_string -from tools.serving.api_providers import anthropic_multiimage_completion, openai_multiimage_completion, gemini_multiimage_completion +from tools.serving.api_providers import ( + anthropic_multiimage_completion, + gemini_multiimage_completion, + openai_multiimage_completion, +) +from tools.utils import ( + build_iteration_content, + extract_planning_prompt, + find_iteration_dirs, + log_output, + read_log_to_string, +) + def tetris_speculator( thread_id, diff --git a/computer_use/games/tetris/tetris_agent.py b/computer_use/games/tetris/tetris_agent.py index 826c6c13..0af3f691 100644 --- a/computer_use/games/tetris/tetris_agent.py +++ b/computer_use/games/tetris/tetris_agent.py @@ -1,10 +1,9 @@ -import time -import numpy as np -import concurrent.futures import argparse +import concurrent.futures +import time -from games.tetris.workers import tetris_worker from games.tetris.speculators import tetris_speculator +from games.tetris.workers import tetris_worker system_prompt = ( "You are an expert AI agent specialized in playing Tetris gameplay, search for and execute optimal moves given each game state. Prioritize line clearing over speed." diff --git a/computer_use/games/tetris/workers.py b/computer_use/games/tetris/workers.py index 889c3314..a781054b 100644 --- a/computer_use/games/tetris/workers.py +++ b/computer_use/games/tetris/workers.py @@ -1,16 +1,31 @@ -import time +import concurrent.futures +import json import os -import pyautogui -import numpy as np - import re -from PIL import Image -import json +import time -import concurrent.futures +import numpy as np +from PIL import Image -from tools.utils import encode_image, log_output, extract_python_code, read_log_to_string, extract_patch_table, extract_game_table, get_annotate_img, get_annotate_patched_img -from tools.serving.api_providers import anthropic_completion, openai_completion, gemini_completion, anthropic_text_completion, openai_text_completion, gemini_text_completion, openai_text_reasoning_completion +from tools.serving.api_providers import ( + anthropic_completion, + anthropic_text_completion, + gemini_completion, + gemini_text_completion, + openai_completion, + openai_text_completion, + openai_text_reasoning_completion, +) +from tools.utils import ( + encode_image, + extract_game_table, + extract_patch_table, + extract_python_code, + get_annotate_img, + get_annotate_patched_img, + log_output, + read_log_to_string, +) color_map = { 0: "Empty", @@ -199,12 +214,12 @@ def tetris_board_reader(system_prompt, api_provider, model_name, image_path, pat "Each block is represented by contiguous blocks with an unique background color.\n" "Only consider the following colors as color-filled:\n" "green = (47, 230, 23), " - "red = (232, 18, 18), " + "red = (232, 18, 18), " "orange = (226, 116, 17), " - "yellow = (237, 234, 4), " - "purple = (166, 0, 247), " - "cyan = (21, 204, 209), " - "light_blue = (59, 85, 162). " + "yellow = (237, 234, 4), " + "purple = (166, 0, 247), " + "cyan = (21, 204, 209), " + "light_blue = (59, 85, 162). " "## The following DO NOT count as color-filled:\n" "1. Dark (deep blue) color background.\n" "2. Green grid lines.\n" @@ -358,7 +373,7 @@ def tetris_worker( # Read information passed from the speculator cache try: # FIXME (lanxiang): make thread count configurable, currently planner is only in thread 0 - experience_summary = read_log_to_string(f"cache/tetris/thread_0/planner/experience_summary.log") + experience_summary = read_log_to_string("cache/tetris/thread_0/planner/experience_summary.log") except Exception as e: experience_summary = "- No lessons learned so far." diff --git a/eval/notebook_utils.py b/eval/notebook_utils.py index 5b87a962..4144d208 100644 --- a/eval/notebook_utils.py +++ b/eval/notebook_utils.py @@ -1,15 +1,16 @@ -import os import glob -import zipfile -import requests import json -import pandas as pd +import os +import random import shutil +import zipfile + import matplotlib.pyplot as plt import numpy as np -import random -import cvxpy as cp -from scipy.optimize import minimize, LinearConstraint +import pandas as pd +import requests +from scipy.optimize import minimize + def check_evaluation_files(download_cache_sample: bool, download_url): report = {"cache_directory": None} # Initialize with None @@ -205,7 +206,7 @@ def generate_evaluation_map(file_info): print(f"An error occurred while processing zip file {cache_location}: {e}") if run_map: - print(f"Info: Map generation from cache completed.") + print("Info: Map generation from cache completed.") else: # This warning will trigger if cache_location was valid but no mappings were found. print(f"Warning: Cache location '{cache_location}' was processed, but no valid agent_config to episode_log mappings were found.") @@ -600,9 +601,9 @@ def polynomial_analysis(x_values, y_values, max_degree=3): Returns: Dictionary with coefficients and R² scores for each degree """ - from sklearn.preprocessing import PolynomialFeatures from sklearn.linear_model import LinearRegression from sklearn.metrics import r2_score + from sklearn.preprocessing import PolynomialFeatures x_array = np.array(x_values).reshape(-1, 1) y_array = np.array(y_values) @@ -902,7 +903,6 @@ def create_comparison_bar_chart(df: pd.DataFrame, model_colors: dict, selected_g def create_game_specific_horizontal_bar_charts(df: pd.DataFrame, model_colors: dict, selected_games: list, harness_status_str: str, highlight_models: list = None): import plotly.graph_objects as go - from plotly.subplots import make_subplots if df.empty: print(f"No data for Game-Specific Bar Charts ({harness_status_str})") @@ -1022,10 +1022,8 @@ def generate_model_performance_plots(final_updated_df: pd.DataFrame, average_res average_results: Optional DataFrame with local results to highlight model_colors_url: Optional URL to fetch model colors JSON """ - import plotly.graph_objects as go + import requests - import json - import random # Default model and game names show_games = list(final_updated_df['game_name'].unique()) @@ -1042,7 +1040,7 @@ def generate_model_performance_plots(final_updated_df: pd.DataFrame, average_res # Load model colors if model_colors_url: - print(f"Attempting to load model colors from URL...") + print("Attempting to load model colors from URL...") try: response = requests.get(model_colors_url) response.raise_for_status() @@ -1315,12 +1313,10 @@ def run_polynomial_analysis_notebook( Dictionary with comprehensive polynomial analysis results """ from itertools import product + + import requests from scipy.stats import rankdata from sklearn.preprocessing import PolynomialFeatures - from sklearn.linear_model import LinearRegression - from sklearn.metrics import r2_score - import requests - import json # Use provided DEFAULT_MODEL_MATCH or fallback to predefined list if DEFAULT_MODEL_MATCH is None: @@ -1904,7 +1900,6 @@ def generate_tsne_visualization(benchmark_df: pd.DataFrame, model_names: list, s """ import matplotlib.pyplot as plt import numpy as np - import pandas as pd from sklearn.manifold import TSNE from sklearn.preprocessing import StandardScaler @@ -1982,9 +1977,8 @@ def generate_benchmark_correlation_matrix(benchmark_df: pd.DataFrame, save_plot: save_plot: Whether to save the plot """ import matplotlib.pyplot as plt - import seaborn as sns import numpy as np - import pandas as pd + import seaborn as sns print("Generating benchmark correlation matrix...") @@ -2199,7 +2193,7 @@ def generate_latent_ability_decomposition(benchmark_df: pd.DataFrame, model_name plt.show() # Print summary - print(f"\nLatent Ability Summary:") + print("\nLatent Ability Summary:") print(f"Total variance explained by {n_components} components: {cumvar[-1]:.1%}") for i in range(n_components): print(f" PC{i+1}: {pca.explained_variance_ratio_[i]:.1%}") @@ -2221,7 +2215,6 @@ def factorize_with_scipy_no_bias(Y, d, lambda_l1=0.01, lambda_l2_m=0.01, lambda_ Low-rank matrix factorization using scipy optimization with improved NaN handling. """ import numpy as np - from scipy.optimize import minimize T, S = Y.shape @@ -2265,7 +2258,6 @@ def factorize_with_scipy_bias(Y, d, lambda_l1=0.01, lambda_l2_m=0.01, lambda_l2_ Low-rank matrix factorization with bias terms using scipy optimization. """ import numpy as np - from scipy.optimize import minimize T, S = Y.shape @@ -2312,8 +2304,8 @@ def generate_simple_tsne_plots(benchmark_data: dict, save_plot: bool = False): """ import matplotlib.pyplot as plt import numpy as np - from sklearn.manifold import TSNE from scipy.stats import rankdata + from sklearn.manifold import TSNE print("Generating simple t-SNE plots...") @@ -2369,8 +2361,8 @@ def generate_simple_correlation_matrix(benchmark_df: pd.DataFrame, save_plot: bo save_plot: Whether to save the plot """ import matplotlib.pyplot as plt - import seaborn as sns import numpy as np + import seaborn as sns print("Generating simple correlation matrix...") @@ -2409,12 +2401,13 @@ def generate_simple_latent_factorization(benchmark_data: dict, benchmark_df: pd. feature_num: Number of latent features save_plot: Whether to save the plot """ + from itertools import chain + import matplotlib.pyplot as plt - import seaborn as sns import numpy as np import pandas as pd + import seaborn as sns from scipy.stats import rankdata - from itertools import chain print(f"Generating latent factorization with {feature_num} features...") diff --git a/eval/replay_utils.py b/eval/replay_utils.py index f79f972c..322c23e0 100644 --- a/eval/replay_utils.py +++ b/eval/replay_utils.py @@ -1,14 +1,15 @@ -import os +import ast import json -import numpy as np -from PIL import Image, ImageDraw, ImageFont -import tempfile +import os +import re import shutil import subprocess -from typing import Optional, Dict, List, Tuple, Union -import ast -import re +import tempfile +from typing import Dict, List, Optional, Tuple + import cv2 +import numpy as np +from PIL import Image, ImageDraw, ImageFont # Default seconds per frame for videos DEFAULT_SECONDS_PER_FRAME = 1.0 @@ -1099,7 +1100,7 @@ def generate_video_from_textual_logs( # Special handling for Pokemon Red - use original images instead of textual representations if game_name.lower() == "pokemon_red": - print(f"Pokemon Red detected - using image-based video generation") + print("Pokemon Red detected - using image-based video generation") return generate_video_from_pokemon_red_images( episode_log_path, output_path, fps, cleanup_frames ) diff --git a/eval/video_generation_script.py b/eval/video_generation_script.py index a57b841a..237bfc1e 100644 --- a/eval/video_generation_script.py +++ b/eval/video_generation_script.py @@ -23,14 +23,15 @@ import argparse import json import os -import sys -import retro import socket import subprocess +import sys import time -import yaml from pathlib import Path -from typing import Dict, Any +from typing import Any, Dict + +import retro +import yaml # Add the current directory to Python path for imports current_dir = Path(__file__).parent.parent @@ -39,6 +40,7 @@ # Import video generation functions from eval.replay_utils import generate_video_from_textual_logs + def playback_movie( emulator, movie, @@ -203,7 +205,7 @@ def render_retro_video(bk2_file_path: str, game_name: str, output_path: str) -> GAMING_AGENT_DIR = os.path.dirname(script_dir) # Handle custom integrations. Ace Attorney has one. - print(f"Setting up retro integration paths...") + print("Setting up retro integration paths...") if game_name == 'ace_attorney': ace_attorney_dir = os.path.join(GAMING_AGENT_DIR, "gamingagent", "envs", "retro_02_ace_attorney") if os.path.exists(ace_attorney_dir): @@ -471,7 +473,7 @@ def main(): sys.exit(1) elif args.method == 'retro': if config_info['game_name'].lower() not in ['ace_attorney', 'super_mario_bros']: - print(f"✗ Retro method is currently only supported for Ace Attorney and Super Mario Bros games") + print("✗ Retro method is currently only supported for Ace Attorney and Super Mario Bros games") sys.exit(1) print("Starting video generation from retro recording...") diff --git a/gamingagent/agents/base_agent.py b/gamingagent/agents/base_agent.py index 5e62a5c9..f998df95 100644 --- a/gamingagent/agents/base_agent.py +++ b/gamingagent/agents/base_agent.py @@ -1,15 +1,13 @@ -import os -import json import datetime -from abc import ABC, abstractmethod -from PIL import Image +import json +import os +from abc import ABC + import numpy as np -import importlib -import inspect -from typing import Optional, Any +from PIL import Image # Import modules -from gamingagent.modules import BaseModule, PerceptionModule, MemoryModule, ReasoningModule, Observation +from gamingagent.modules import BaseModule, MemoryModule, Observation GAMES_REQUIRE_HARNESS = [ "pokemon_red", @@ -355,7 +353,7 @@ def save_obs(self, observation, filename=None): print(f"Warning: Observation shape {observation.shape} doesn't match image format.") return None else: - print(f"Warning: Observation is not a numpy array, cannot save as image.") + print("Warning: Observation is not a numpy array, cannot save as image.") return None def get_action(self, observation): diff --git a/gamingagent/envs/__init__.py b/gamingagent/envs/__init__.py index d75b1230..e94f9e87 100644 --- a/gamingagent/envs/__init__.py +++ b/gamingagent/envs/__init__.py @@ -1,9 +1,7 @@ # Main adapter for integrating gym environments with the agent's expected interaction loop -from .gym_env_adapter import GymEnvAdapter - # Utility functions for environments, e.g., image generation from .env_utils import create_board_image_2048 - +from .gym_env_adapter import GymEnvAdapter __all__ = [ "GymEnvAdapter", diff --git a/gamingagent/envs/custom_01_2048/twentyFortyEightEnv.py b/gamingagent/envs/custom_01_2048/twentyFortyEightEnv.py index 7ddb2df3..d1c15360 100644 --- a/gamingagent/envs/custom_01_2048/twentyFortyEightEnv.py +++ b/gamingagent/envs/custom_01_2048/twentyFortyEightEnv.py @@ -1,18 +1,19 @@ # Credits to https://github.com/Quentin18/gymnasium-2048/tree/main for the original 2048 game implementation. # We thank the author for their work, which serves as an excellent testbed for our agent. -from typing import Any, Dict, Tuple, Optional, List +from typing import Any, Dict, Optional import gymnasium as gym import numpy as np import pygame from gymnasium import spaces -from gymnasium.core import ActType, ObsType, RenderFrame, SupportsFloat +from gymnasium.core import ActType, RenderFrame, SupportsFloat + +from gamingagent.envs.env_utils import create_board_image_2048 # Ensure this is imported # Import the adapter and Observation dataclass from gamingagent.envs.gym_env_adapter import GymEnvAdapter from gamingagent.modules.core_module import Observation -from gamingagent.envs.env_utils import create_board_image_2048 # Ensure this is imported WINDOW_WIDTH = 400 WINDOW_HEIGHT = 400 diff --git a/gamingagent/envs/custom_02_sokoban/sokobanEnv.py b/gamingagent/envs/custom_02_sokoban/sokobanEnv.py index 3d1c2ac8..6c235f56 100644 --- a/gamingagent/envs/custom_02_sokoban/sokobanEnv.py +++ b/gamingagent/envs/custom_02_sokoban/sokobanEnv.py @@ -1,16 +1,16 @@ +import os +import re # For parsing levels.txt +from typing import Any, Dict, List, Optional, Tuple, Union + import gymnasium as gym import numpy as np -import os -import pygame # For rendering -from PIL import Image, ImageDraw, ImageFont -from typing import Any, Dict, Tuple, Optional, List, Union -import json -import re # For parsing levels.txt +import pygame # For rendering +from gymnasium.core import RenderFrame +from gymnasium.spaces import Box, Discrete +from PIL import Image, ImageDraw, ImageFont from gamingagent.envs.gym_env_adapter import GymEnvAdapter from gamingagent.modules.core_module import Observation -from gymnasium.spaces import Discrete, Box -from gymnasium.core import RenderFrame # It's better to move create_board_image_sokoban to env_utils if it's generic enough, # but for now, let's assume it's defined here or imported from a local helper. diff --git a/gamingagent/envs/custom_03_candy_crush/candyCrushEnv.py b/gamingagent/envs/custom_03_candy_crush/candyCrushEnv.py index 3bfb32f5..d87593ae 100644 --- a/gamingagent/envs/custom_03_candy_crush/candyCrushEnv.py +++ b/gamingagent/envs/custom_03_candy_crush/candyCrushEnv.py @@ -1,25 +1,25 @@ -import gymnasium as gym -import numpy as np -import os import json +import os import re -from typing import Any, Dict, Tuple, Optional, List, Union -from PIL import Image, ImageDraw, ImageFont -import hashlib + # import imageio # Commented out for now # import tempfile # Commented out for now # import shutil # Commented out for now from collections import OrderedDict +from typing import Any, Dict, List, Optional, Tuple, Union -from gamingagent.modules.core_module import Observation -from gamingagent.envs.gym_env_adapter import GymEnvAdapter # Added -from gymnasium.spaces import Discrete, Box +import gymnasium as gym +import numpy as np +from gymnasium.spaces import Box, Discrete +from PIL import Image, ImageDraw, ImageFont # Imports from TileMatchEnv -from tile_match_gym.board import Board -from tile_match_gym.board import is_move_effective +from tile_match_gym.board import Board, is_move_effective from tile_match_gym.renderer import Renderer +from gamingagent.envs.gym_env_adapter import GymEnvAdapter # Added +from gamingagent.modules.core_module import Observation + # Define constants for Candy Crush elements (example) # These should match what TileMatchEnv uses or how you want to represent them textually COLOR_MAP = { diff --git a/gamingagent/envs/custom_03_candy_crush/tile_match_gym/board.py b/gamingagent/envs/custom_03_candy_crush/tile_match_gym/board.py index d02c4c2e..8dfdab2f 100644 --- a/gamingagent/envs/custom_03_candy_crush/tile_match_gym/board.py +++ b/gamingagent/envs/custom_03_candy_crush/tile_match_gym/board.py @@ -1,8 +1,8 @@ -import numpy as np +from typing import List, Optional, Tuple + import numba +import numpy as np from numba import njit, types -from typing import Optional, List, Tuple - """ tile_colours = { diff --git a/gamingagent/envs/custom_03_candy_crush/tile_match_gym/tile_match_env.py b/gamingagent/envs/custom_03_candy_crush/tile_match_gym/tile_match_env.py index 367796eb..422aa544 100644 --- a/gamingagent/envs/custom_03_candy_crush/tile_match_gym/tile_match_env.py +++ b/gamingagent/envs/custom_03_candy_crush/tile_match_gym/tile_match_env.py @@ -1,13 +1,11 @@ -import gymnasium as gym -import numpy as np - -from gymnasium.spaces import Discrete, Box -from typing import Optional, List, Tuple, Union from collections import OrderedDict +from typing import List, Optional, Tuple, Union -from tile_match_gym.board import Board -from tile_match_gym.board import is_move_effective +import gymnasium as gym +import numpy as np +from gymnasium.spaces import Box, Discrete +from tile_match_gym.board import Board, is_move_effective from tile_match_gym.renderer import Renderer diff --git a/gamingagent/envs/custom_03_candy_crush/tile_match_gym/utils/utils.py b/gamingagent/envs/custom_03_candy_crush/tile_match_gym/utils/utils.py index b6dfc972..9e5366fd 100644 --- a/gamingagent/envs/custom_03_candy_crush/tile_match_gym/utils/utils.py +++ b/gamingagent/envs/custom_03_candy_crush/tile_match_gym/utils/utils.py @@ -1,7 +1,10 @@ -from tile_match_gym.board import Board +import multiprocessing as mp from itertools import product + import numpy as np -import multiprocessing as mp + +from tile_match_gym.board import Board + def compute_num_states(num_rows, num_cols, num_colours, num_processes, colour_specials=[], colourless_specials=[]): diff --git a/gamingagent/envs/custom_03_candy_crush/tile_match_gym/wrappers.py b/gamingagent/envs/custom_03_candy_crush/tile_match_gym/wrappers.py index 6bccbb68..736aba73 100644 --- a/gamingagent/envs/custom_03_candy_crush/tile_match_gym/wrappers.py +++ b/gamingagent/envs/custom_03_candy_crush/tile_match_gym/wrappers.py @@ -1,9 +1,9 @@ -from gymnasium import ObservationWrapper, RewardWrapper from collections import OrderedDict -from gymnasium.spaces import Box import gymnasium as gym import numpy as np +from gymnasium import ObservationWrapper, RewardWrapper +from gymnasium.spaces import Box # Have to use these because the special types have hardcoded ids in the environment. COLOURLESS_SPECIALS = {"cookie": -1} @@ -80,7 +80,7 @@ def reward(self, reward: float): if __name__=="__main__": import gymnasium as gym - import tile_match_gym + env = gym.make("TileMatch-v0", num_rows=5, num_cols=4, num_colours=2, num_moves = 10, colour_specials=["vertical_laser", "horizontal_laser", "bomb"], colourless_specials=["cookie"], seed=2) env = OneHotWrapper(ProportionRewardWrapper(env)) diff --git a/gamingagent/envs/custom_04_tetris/tetrisEnv.py b/gamingagent/envs/custom_04_tetris/tetrisEnv.py index 44814ec4..f2f69c5e 100644 --- a/gamingagent/envs/custom_04_tetris/tetrisEnv.py +++ b/gamingagent/envs/custom_04_tetris/tetrisEnv.py @@ -1,19 +1,18 @@ -import gymnasium as gym -import numpy as np - import copy -from dataclasses import dataclass -from typing import Optional, Dict, Any, Tuple, SupportsFloat, List -from gymnasium.core import RenderFrame - -import cv2 # For rendering 'human' mode - import os import re +from dataclasses import dataclass +from typing import Any, Dict, List, Optional, SupportsFloat, Tuple +import cv2 # For rendering 'human' mode +import gymnasium as gym +import numpy as np +from gymnasium.core import RenderFrame + +from gamingagent.envs.env_utils import create_board_image_tetris from gamingagent.envs.gym_env_adapter import GymEnvAdapter from gamingagent.modules.core_module import Observation -from gamingagent.envs.env_utils import create_board_image_tetris + # --- Core Tetris Components with Color --- @dataclass @@ -395,7 +394,7 @@ def _get_all_rotations_text_representations(self) -> str: for r_idx in range(max_rotations): if r_idx == 0: - rotations_text += f"Rotation 0 (Canonical Base):\n" + rotations_text += "Rotation 0 (Canonical Base):\n" else: rotations_text += f"Rotation {r_idx} (Base + {r_idx} clockwise):\n" @@ -436,8 +435,8 @@ def reset(self, *, seed: Optional[int]=None, options: Optional[Dict[str,Any]]=No self._fill_piece_queue() self.board = self._create_board() - self.game_over=False; - self.current_score=0.0; + self.game_over=False + self.current_score=0.0 self.total_perf_score_episode = 0.0 # NEW: Reset total perf score for the episode self.lines_cleared_total=0; self.level=1; self.x=0; self.y=0 self.active_tetromino_original_idx = None diff --git a/gamingagent/envs/custom_05_doom/doomEnv.py b/gamingagent/envs/custom_05_doom/doomEnv.py index 42849c6b..86897ac2 100644 --- a/gamingagent/envs/custom_05_doom/doomEnv.py +++ b/gamingagent/envs/custom_05_doom/doomEnv.py @@ -1,25 +1,24 @@ from __future__ import annotations -import os +import datetime +import faulthandler import json import logging +import os +import random import sys import time -import faulthandler -from typing import Any, Dict, List, Tuple, Optional -import datetime -import random -import cv2 -import psutil # Add psutil import for memory usage logging -import math +from typing import Any, Dict, List, Optional, Tuple +import cv2 +import gymnasium as gym import numpy as np +import psutil # Add psutil import for memory usage logging import vizdoom as vzd -import gymnasium as gym from gymnasium import spaces from gamingagent.envs.gym_env_adapter import GymEnvAdapter -from gamingagent.modules.core_module import Observation, GameTrajectory +from gamingagent.modules.core_module import GameTrajectory, Observation # Enable fault handler for better crash information faulthandler.enable() diff --git a/gamingagent/envs/custom_06_pokemon_red/full_collision_map.py b/gamingagent/envs/custom_06_pokemon_red/full_collision_map.py index ba6f6988..97ec506b 100644 --- a/gamingagent/envs/custom_06_pokemon_red/full_collision_map.py +++ b/gamingagent/envs/custom_06_pokemon_red/full_collision_map.py @@ -1,6 +1,7 @@ -import numpy as np -from typing import Optional, Dict, Tuple, List, Set import os +from typing import Dict, List, Optional, Set, Tuple + +import numpy as np class LocationCollisionMap: diff --git a/gamingagent/envs/custom_06_pokemon_red/pokemonRedEnv.py b/gamingagent/envs/custom_06_pokemon_red/pokemonRedEnv.py index 77a2d16e..3f48a6be 100644 --- a/gamingagent/envs/custom_06_pokemon_red/pokemonRedEnv.py +++ b/gamingagent/envs/custom_06_pokemon_red/pokemonRedEnv.py @@ -1,23 +1,21 @@ # TODO: Define reward for each step - Yuxuan -import io -import pickle -from collections import deque +import base64 import heapq -from typing import Optional, Dict, Any, Tuple, List +import io import os -import base64 +from typing import Any, Dict, List, Optional, Tuple -from .memory_reader import PokemonRedReader, StatusCondition -from .full_collision_map import LocationCollisionMap +import numpy as np +from gymnasium import Env, spaces from PIL import Image, ImageDraw from pyboy import PyBoy -from gymnasium import Env, spaces -import numpy as np - from gamingagent.envs.gym_env_adapter import GymEnvAdapter from gamingagent.modules.core_module import Observation +from .full_collision_map import LocationCollisionMap +from .memory_reader import PokemonRedReader, StatusCondition + class PokemonRedEnv(Env): def __init__(self, @@ -867,7 +865,7 @@ def reconstruct_path(current): is_wall = terrain[end[0]][end[1]] == 0 if is_wall: return ( - f"Partial Success: Your target location is a wall. In case this is intentional, attempting to navigate there.", + "Partial Success: Your target location is a wall. In case this is intentional, attempting to navigate there.", path, ) else: @@ -944,7 +942,7 @@ def reconstruct_path(current): if closest_point != start: path = reconstruct_path(closest_point) return ( - f"Partial Success: Could not reach the exact target, but found a path to the closest reachable point.", + "Partial Success: Could not reach the exact target, but found a path to the closest reachable point.", path, ) diff --git a/gamingagent/envs/env_utils.py b/gamingagent/envs/env_utils.py index 33fd9a6d..40fcf9c4 100644 --- a/gamingagent/envs/env_utils.py +++ b/gamingagent/envs/env_utils.py @@ -1,7 +1,8 @@ -import numpy as np import os +from typing import Any, Dict, List, Optional + +import numpy as np from PIL import Image, ImageDraw, ImageFont -from typing import Optional, Dict, List, Any # Color mapping for different tile values (extended from user's example) COLORS = { @@ -191,7 +192,7 @@ def create_board_image_tetris( return if not pixel_color_mapping: - print(f"[create_board_image_tetris] Error: pixel_color_mapping is empty or None. Cannot determine piece colors.") + print("[create_board_image_tetris] Error: pixel_color_mapping is empty or None. Cannot determine piece colors.") return empty_color_val_id = 0 # Assuming 0 is the ID for empty space, used for comparison diff --git a/gamingagent/envs/gym_env_adapter.py b/gamingagent/envs/gym_env_adapter.py index 2792093a..cd88a1d6 100644 --- a/gamingagent/envs/gym_env_adapter.py +++ b/gamingagent/envs/gym_env_adapter.py @@ -1,8 +1,8 @@ -import os -import json -import datetime import hashlib -from typing import Optional, Dict, Any, Tuple, List +import json +import os +from typing import Any, Dict, List, Optional, Tuple + import numpy as np from gamingagent.modules.core_module import Observation @@ -251,7 +251,7 @@ def log_step_data(self, agent_action_str: Optional[str], thought_process: str, r except Exception as e: print(f"[GymEnvAdapter] CRITICAL ERROR (Log Write): Failed to write log_entry. Details: {e}") else: - print(f"[GymEnvAdapter] Warning: Episode log file handle is None. Cannot write log.") + print("[GymEnvAdapter] Warning: Episode log file handle is None. Cannot write log.") def verify_termination(self, agent_observation: Observation, current_terminated: bool, current_truncated: bool) -> Tuple[bool, bool]: """ diff --git a/gamingagent/envs/retro_01_super_mario_bros/superMarioBrosEnv.py b/gamingagent/envs/retro_01_super_mario_bros/superMarioBrosEnv.py index fb3c5aed..3ecb95bf 100644 --- a/gamingagent/envs/retro_01_super_mario_bros/superMarioBrosEnv.py +++ b/gamingagent/envs/retro_01_super_mario_bros/superMarioBrosEnv.py @@ -1,14 +1,15 @@ -import os import json -from typing import Any, Dict, Tuple, Optional, List, Union +import os +from typing import Any, Dict, List, Optional, Tuple -import retro import numpy as np -from PIL import Image # For saving frames +import retro +from PIL import Image # For saving frames -from gamingagent.envs.gym_env_adapter import GymEnvAdapter # Changed from RetroEnvAdapter +from gamingagent.envs.gym_env_adapter import GymEnvAdapter # Changed from RetroEnvAdapter from gamingagent.modules.core_module import Observation + class SuperMarioBrosEnv: """ A wrapper for the Super Mario Bros retro environment. @@ -167,7 +168,7 @@ def _build_textual_representation_for_log(self, game_info: Dict[str, Any]) -> Op if "ram_lives_value" in game_info: if game_info["ram_lives_value"] == 255: - parts.append(f"Lives (RAM): 0 (Game Over Screen)") + parts.append("Lives (RAM): 0 (Game Over Screen)") else: parts.append(f"Lives (RAM): {game_info['ram_lives_value'] + 1}") diff --git a/gamingagent/envs/retro_02_ace_attorney/aceAttorneyEnv.py b/gamingagent/envs/retro_02_ace_attorney/aceAttorneyEnv.py index afc55b83..82b02832 100644 --- a/gamingagent/envs/retro_02_ace_attorney/aceAttorneyEnv.py +++ b/gamingagent/envs/retro_02_ace_attorney/aceAttorneyEnv.py @@ -1,20 +1,20 @@ -import retro -from retro.enums import Actions, Observations # type: ignore -import gymnasium as gym # type: ignore -from gymnasium.core import SupportsFloat, RenderFrame # type: ignore -import numpy as np # type: ignore -from PIL import Image # type: ignore -import time +import atexit # ADDED IMPORT import json import os -import hashlib -import re # For keyword mapping -from typing import Optional, Dict, Any, Tuple, List -import pyglet # ADDED IMPORT -import atexit # ADDED IMPORT +import re # For keyword mapping +import time +from typing import Any, Dict, List, Optional, Tuple + +import gymnasium as gym # type: ignore +import numpy as np # type: ignore +import retro +from gymnasium.core import RenderFrame, SupportsFloat # type: ignore +from PIL import Image # type: ignore +from retro.enums import Actions, Observations # type: ignore -from gamingagent.modules.core_module import Observation from gamingagent.envs.gym_env_adapter import GymEnvAdapter +from gamingagent.modules.core_module import Observation + # from gamingagent.envs.env_utils import create_board_image_ace_attorney # If visual representation needed beyond raw pixels # --- Constants --- @@ -846,7 +846,7 @@ def prepare_prompt(self, base_prompt: str) -> Tuple[str, Optional[str]]: def close(self): """Closes the environment and the adapter's log file. Called by atexit.""" - print(f"[AceAttorneyEnv CLOSE] Closing environment and saving recording...") + print("[AceAttorneyEnv CLOSE] Closing environment and saving recording...") try: self.env.close() print("[AceAttorneyEnv CLOSE] Environment closed successfully.") diff --git a/gamingagent/envs/retro_02_ace_attorney/test.py b/gamingagent/envs/retro_02_ace_attorney/test.py index 5fc91b28..df92364f 100644 --- a/gamingagent/envs/retro_02_ace_attorney/test.py +++ b/gamingagent/envs/retro_02_ace_attorney/test.py @@ -1,7 +1,8 @@ -import retro import os -import pygame # For keyboard input + import numpy as np +import pygame # For keyboard input +import retro SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) @@ -83,7 +84,7 @@ def main(): print(f"'{game_name}' not found. Please ensure:") print(f"1. The game folder is named '{game_name}'.") print(f"2. It is located at: {os.path.join(SCRIPT_DIR, game_name)}") - print(f"3. It contains rom, data.json, scenario.json, etc.") + print("3. It contains rom, data.json, scenario.json, etc.") return print(f"Attempting to make environment for '{game_name}'...") @@ -109,13 +110,13 @@ def main(): pygame.display.set_caption("Keyboard Input Helper") print("\nControls (Keyboard -> GBA Button Index -> GBA Button Name based on env.buttons):") - print(f" Keyboard 'A' -> Index 8 (GBA 'A')") - print(f" Keyboard 'B' -> Index 0 (GBA 'B')") - print(f" Keyboard 'L' -> Index 10 (GBA 'L')") - print(f" Keyboard 'R' -> Index 11 (GBA 'R')") - print(f" Arrow Keys -> Indices 4-7 (GBA D-Pad)") - print(f" Enter Key -> Index 3 (GBA 'Start')") - print(f" Backspace -> Index 2 (GBA 'Select')") + print(" Keyboard 'A' -> Index 8 (GBA 'A')") + print(" Keyboard 'B' -> Index 0 (GBA 'B')") + print(" Keyboard 'L' -> Index 10 (GBA 'L')") + print(" Keyboard 'R' -> Index 11 (GBA 'R')") + print(" Arrow Keys -> Indices 4-7 (GBA D-Pad)") + print(" Enter Key -> Index 3 (GBA 'Start')") + print(" Backspace -> Index 2 (GBA 'Select')") print("Press ESC in Pygame window or Ctrl+C in terminal to quit.") running = True diff --git a/gamingagent/envs/retro_03_1942/NineteenFortyTwo_env.py b/gamingagent/envs/retro_03_1942/NineteenFortyTwo_env.py index a72e5aad..44f57514 100644 --- a/gamingagent/envs/retro_03_1942/NineteenFortyTwo_env.py +++ b/gamingagent/envs/retro_03_1942/NineteenFortyTwo_env.py @@ -1,15 +1,15 @@ from __future__ import annotations -import os, json, hashlib -from typing import Any, Dict, List, Tuple, Optional +import hashlib +import json +import os +from typing import Any, Dict, List, Optional -import retro -import numpy as np -from PIL import Image import gymnasium as gym +import numpy as np +import retro from gamingagent.envs.gym_env_adapter import GymEnvAdapter -from gamingagent.modules.core_module import Observation __all__ = ["NineteenFortyTwoEnv"] diff --git a/gamingagent/envs/zoo_01_tictactoe/TicTacToeEnv.py b/gamingagent/envs/zoo_01_tictactoe/TicTacToeEnv.py index f770efac..b5dcaf64 100644 --- a/gamingagent/envs/zoo_01_tictactoe/TicTacToeEnv.py +++ b/gamingagent/envs/zoo_01_tictactoe/TicTacToeEnv.py @@ -27,16 +27,16 @@ import os import random -from typing import Any, Dict, List, Optional, Tuple, Union, Callable +from typing import Any, Callable, Dict, List, Optional, Tuple, Union import gymnasium as gym +import imageio import numpy as np import pygame -from PIL import Image, ImageDraw, ImageFont -import imageio from gymnasium.core import RenderFrame from gymnasium.spaces import Box, Discrete from pettingzoo.classic import tictactoe_v3 +from PIL import Image, ImageDraw, ImageFont from gamingagent.envs.gym_env_adapter import GymEnvAdapter from gamingagent.modules.core_module import Observation diff --git a/gamingagent/envs/zoo_02_texasholdem/TexasHoldemEnv.py b/gamingagent/envs/zoo_02_texasholdem/TexasHoldemEnv.py index 90c42549..ca70693f 100644 --- a/gamingagent/envs/zoo_02_texasholdem/TexasHoldemEnv.py +++ b/gamingagent/envs/zoo_02_texasholdem/TexasHoldemEnv.py @@ -6,22 +6,22 @@ """ from __future__ import annotations + +import json import os import random -from typing import Any, Dict, List, Optional, Tuple, Union, Callable +from typing import Any, Callable, Dict, List, Optional, Tuple, Union import gymnasium as gym +import imageio import numpy as np from gymnasium.spaces import Box, Discrete from pettingzoo.classic import texas_holdem_v4 from PIL import Image, ImageDraw, ImageFont -import imageio -import glob -from natsort import natsorted -import json from gamingagent.envs.gym_env_adapter import GymEnvAdapter from gamingagent.modules.core_module import Observation + # --------------------------------------------------------------------------- # Helper utilities for optional text observation # --------------------------------------------------------------------------- diff --git a/gamingagent/modules/__init__.py b/gamingagent/modules/__init__.py index 7b908715..f03aa77c 100644 --- a/gamingagent/modules/__init__.py +++ b/gamingagent/modules/__init__.py @@ -1,5 +1,5 @@ -from .core_module import CoreModule, Observation from .base_module import BaseModule +from .core_module import CoreModule, Observation from .memory_module import MemoryModule from .perception_module import PerceptionModule from .reasoning_module import ReasoningModule diff --git a/gamingagent/modules/base_module.py b/gamingagent/modules/base_module.py index ba71b9d1..71df8c5d 100644 --- a/gamingagent/modules/base_module.py +++ b/gamingagent/modules/base_module.py @@ -1,10 +1,9 @@ -import numpy as np -from abc import abstractmethod -from .core_module import CoreModule, Observation -from tools.utils import scale_image_up import re -import os -import time + +from tools.utils import scale_image_up + +from .core_module import CoreModule + class BaseModule(CoreModule): """ diff --git a/gamingagent/modules/core_module.py b/gamingagent/modules/core_module.py index 1cb55833..f006fed5 100644 --- a/gamingagent/modules/core_module.py +++ b/gamingagent/modules/core_module.py @@ -1,14 +1,15 @@ +import datetime import json import os -import datetime +import string from abc import ABC, abstractmethod -from tools.serving import APIManager +from collections import deque from dataclasses import dataclass -from typing import Optional, Dict, Any +from typing import Optional + +from tools.serving import APIManager -from collections import deque -import string ######################################################################################## #TODO: Add grid_size to observation for perception module to draw the grid on the image# ######################################################################################## diff --git a/gamingagent/modules/memory_module.py b/gamingagent/modules/memory_module.py index dfee4616..24de7549 100644 --- a/gamingagent/modules/memory_module.py +++ b/gamingagent/modules/memory_module.py @@ -1,10 +1,11 @@ -import os -import json -import time import datetime +import json +import os import re + from .core_module import CoreModule, GameTrajectory, Observation + class MemoryModule(CoreModule): """ A lightweight memory module: @@ -131,7 +132,7 @@ def _summarize(self, game_trajectory: str) -> str: ) try: - print(f"[MemoryModule] Generating summary...") + print("[MemoryModule] Generating summary...") raw = self.api_manager.text_only_completion( model_name=self.model_name, @@ -162,7 +163,7 @@ def _summarize(self, game_trajectory: str) -> str: print(f"[MemoryModule] Error generating summary: {e}") # Return a basic fallback summary fallback_summary = f"FALLBACK SUMMARY: Game trajectory contained {len(game_trajectory)} characters of gameplay data. Previous summary: {self.current_summary[:200] if self.current_summary else 'None'}..." - print(f"[MemoryModule] Using fallback summary due to error.") + print("[MemoryModule] Using fallback summary due to error.") return fallback_summary def process_observation(self, observation: Observation) -> str: @@ -262,7 +263,7 @@ def update_observation_memory(self, observation: Observation) -> str: print(f"[MemoryModule] Successfully generated and saved summary. Length: {len(self.current_summary)} chars") else: - print(f"[MemoryModule] Failed to generate valid summary after all retries. Keeping existing trajectory.") + print("[MemoryModule] Failed to generate valid summary after all retries. Keeping existing trajectory.") else: print(f"[MemoryModule] Insufficient trajectory content ({len(current_trajectory)} chars) for summarization. Skipping.") diff --git a/gamingagent/modules/perception_module.py b/gamingagent/modules/perception_module.py index 07f5a5ce..f35182a4 100644 --- a/gamingagent/modules/perception_module.py +++ b/gamingagent/modules/perception_module.py @@ -1,15 +1,14 @@ -import numpy as np +import copy import os -import json -import datetime -from abc import ABC, abstractmethod -from PIL import Image -from .core_module import CoreModule, Observation -import copy +import numpy as np +from PIL import Image from tools.utils import scale_image_up +from .core_module import CoreModule, Observation + + class PerceptionModule(CoreModule): """ Perception module that analyzes game state to extract relevant features. diff --git a/gamingagent/modules/prompt_graph.py b/gamingagent/modules/prompt_graph.py index fb0184d1..c71d0b06 100644 --- a/gamingagent/modules/prompt_graph.py +++ b/gamingagent/modules/prompt_graph.py @@ -1,10 +1,12 @@ import hashlib -import os import json +import os from datetime import datetime -from typing import List, Dict, Optional, Any +from typing import Any, Dict, Optional + from graphviz import Digraph + class PromptNode: """ Represents a single node in the prompt graph. diff --git a/gamingagent/modules/reasoning_module.py b/gamingagent/modules/reasoning_module.py index c77df1f3..f13af0af 100644 --- a/gamingagent/modules/reasoning_module.py +++ b/gamingagent/modules/reasoning_module.py @@ -1,9 +1,8 @@ -from abc import abstractmethod -from .core_module import CoreModule, Observation - import re + from tools.utils import scale_image_up -import time + +from .core_module import CoreModule # TODO: # 1.module integration diff --git a/lmgame-bench/multi_agent_runner.py b/lmgame-bench/multi_agent_runner.py index 1c0986ef..dea91764 100644 --- a/lmgame-bench/multi_agent_runner.py +++ b/lmgame-bench/multi_agent_runner.py @@ -1,4 +1,5 @@ from __future__ import annotations + """ multiagent_tictactoe_runner.py – final complete version ====================================================== @@ -7,16 +8,15 @@ import argparse import datetime as _dt +import json import os +import sys import time -from typing import Any, Dict, Optional +from pathlib import Path +from typing import Optional -import yaml import trueskill -import sys - -import json -from pathlib import Path +import yaml from gamingagent.agents.base_agent import BaseAgent from gamingagent.envs.zoo_01_tictactoe.TicTacToeEnv import MultiTicTacToeEnv @@ -442,7 +442,7 @@ def play_episode(env, agents, eid, max_turns, seed): print(f"Result: {result}") # Show move history - print(f"\nMove History:") + print("\nMove History:") for move in moves_log: print(f" {move}") @@ -736,8 +736,8 @@ def _prompt_for_player(player_index: int) -> Optional[str]: ordered = sorted(final_chip_counts.items(), key=lambda kv: kv[1], reverse=True) if is_tournament_end: - print(f"\n🏆 TOURNAMENT FINAL RANKING - Updating TrueSkill based on final chip stacks") - print(f"Final chip standings:") + print("\n🏆 TOURNAMENT FINAL RANKING - Updating TrueSkill based on final chip stacks") + print("Final chip standings:") for i, (player, chips) in enumerate(ordered, 1): print(f" #{i}: {player} - {chips:,.0f} chips") # Print Aggression Factor summary @@ -801,7 +801,7 @@ def _prompt_for_player(player_index: int) -> Optional[str]: weighted_ranks.append(weighted_rank) post_ratings = ts.rate(pre_ratings, ranks=weighted_ranks) - print(f"Applied TrueSkill 2 updates based on cumulative tournament performance") + print("Applied TrueSkill 2 updates based on cumulative tournament performance") else: # Standard TrueSkill for non-poker games post_ratings = ts.rate(pre_ratings, ranks=ranks) @@ -893,13 +893,13 @@ def _prompt_for_player(player_index: int) -> Optional[str]: # Show model assignments if using player_models if args.player_models and len(args.player_models) > 1: - print(f"\nModel Assignments:") + print("\nModel Assignments:") for i, model in enumerate(args.player_models): player_key = f"player_{i}" if args.game_name.lower() == "texasholdem" else f"player_{i+1}" print(f" {player_key}: {model}") # Print final TrueSkill leaderboard - print(f"\n--- FINAL TRUESKILL RANKING ---") + print("\n--- FINAL TRUESKILL RANKING ---") sorted_ratings = sorted(ratings.items(), key=lambda item: trueskill.expose(item[1]), reverse=True) for rank, (agent_key, rating) in enumerate(sorted_ratings, 1): exposed_rating = trueskill.expose(rating) diff --git a/lmgame-bench/run.py b/lmgame-bench/run.py index 98908a9e..9e868dd9 100644 --- a/lmgame-bench/run.py +++ b/lmgame-bench/run.py @@ -1,11 +1,11 @@ import argparse -import subprocess +import multiprocessing import os +import subprocess import sys -import multiprocessing -from typing import List, Tuple -from concurrent.futures import ProcessPoolExecutor, as_completed import time +from concurrent.futures import ProcessPoolExecutor, as_completed +from typing import Tuple # python run.py --model_name gemini-2.0-flash --game_names sokoban,tetris,candy_crush,twenty_forty_eight,super_mario_bros --harness_mode both diff --git a/lmgame-bench/single_agent_runner.py b/lmgame-bench/single_agent_runner.py index d5b05167..b4cfd78a 100644 --- a/lmgame-bench/single_agent_runner.py +++ b/lmgame-bench/single_agent_runner.py @@ -1,25 +1,18 @@ import argparse -import os -import json import datetime -import time -import numpy as np -import yaml -from typing import Any +import json +import os import sys -import re -import random - -import gymnasium as gym - +import time from typing import Any, Dict +import gymnasium as gym import retro -from retro.enums import Actions, Observations, State # retro.data will be used directly for Integrations +import yaml +from retro.enums import Actions, Observations, State # retro.data will be used directly for Integrations from gamingagent.agents.base_agent import BaseAgent -from gamingagent.modules import PerceptionModule, ReasoningModule # Observation is imported by Env -from tools.utils import draw_grid_on_image + # Directly import the specific environment we are using from gamingagent.envs.custom_01_2048.twentyFortyEightEnv import TwentyFortyEightEnv from gamingagent.envs.custom_02_sokoban.sokobanEnv import SokobanEnv @@ -27,12 +20,12 @@ from gamingagent.envs.custom_04_tetris.tetrisEnv import TetrisEnv from gamingagent.envs.custom_05_doom.doomEnv import DoomEnvWrapper from gamingagent.envs.custom_06_pokemon_red.pokemonRedEnv import PokemonRedEnv - from gamingagent.envs.retro_01_super_mario_bros.superMarioBrosEnv import SuperMarioBrosEnv from gamingagent.envs.retro_02_ace_attorney.aceAttorneyEnv import AceAttorneyEnv from gamingagent.envs.retro_03_1942.NineteenFortyTwo_env import NineteenFortyTwoEnv - from gamingagent.envs.zoo_01_tictactoe.TicTacToeEnv import SingleTicTacToeEnv +from gamingagent.modules import PerceptionModule, ReasoningModule # Observation is imported by Env +from tools.utils import draw_grid_on_image game_config_mapping = { "twenty_forty_eight": "custom_01_2048", diff --git a/pyproject.toml b/pyproject.toml index c9b726d2..833f22f7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,3 +45,14 @@ repository = "https://github.com/lmgame-org/GamingAgent" [tool.pdm] distribution = true + +[tool.ruff] +line-length = 120 +extend-exclude = ["*.ipynb"] + +[tool.ruff.lint] +select = ["E", "F", "I"] +ignore = ["E501", "E402", "E731", "E722", "E741", "E721", "E701", "E702", "F841", "F403", "F405", "F821", "F811", "E712"] + +[tool.ruff.lint.per-file-ignores] +"__init__.py" = ["F401"] diff --git a/tests/pokemon_red_test/test_game_env.py b/tests/pokemon_red_test/test_game_env.py index e3ec8856..3eca58e6 100644 --- a/tests/pokemon_red_test/test_game_env.py +++ b/tests/pokemon_red_test/test_game_env.py @@ -1,6 +1,3 @@ -import random -import time -import numpy as np from gamingagent.envs.custom_05_pokemon_red.pokemonRedEnv import PokemonRedEnv @@ -15,7 +12,7 @@ def test_random_play(): print("Resetting environment...") obs, info = env.reset() - print(f"✓ Environment reset successful") + print("✓ Environment reset successful") print(f" Observation type: {type(obs)}") print(f" Has image path: {obs.img_path is not None}") print(f" Info keys: {list(info.keys())}") diff --git a/tests/test_agents/modules/doom_base_module.py b/tests/test_agents/modules/doom_base_module.py index a3261c6c..ce97f0e1 100644 --- a/tests/test_agents/modules/doom_base_module.py +++ b/tests/test_agents/modules/doom_base_module.py @@ -1,11 +1,14 @@ -import numpy as np import logging + +import numpy as np + from tools.serving import APIManager + def load_module_prompts(): """Load module prompts from config file.""" - import os import json + import os config_paths = [ os.path.join("configs", "custom_05_doom", "module_prompts.json"), diff --git a/tests/test_run.py b/tests/test_run.py index a9db1f55..644b8fdd 100644 --- a/tests/test_run.py +++ b/tests/test_run.py @@ -1,11 +1,11 @@ -import pytest -import sys import os +import shutil import subprocess +import sys import tempfile -import shutil -from unittest.mock import Mock, patch, MagicMock -from concurrent.futures import Future +from unittest.mock import Mock, patch + +import pytest # Add the parent directory to sys.path to import the run module sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'lmgame-bench')) diff --git a/tools/modal/serve_instance.py b/tools/modal/serve_instance.py index fa4be4dc..387b9d03 100644 --- a/tools/modal/serve_instance.py +++ b/tools/modal/serve_instance.py @@ -1,6 +1,8 @@ -import modal import os +import modal + + # -------- # Get config from environment variables # -------- diff --git a/tools/modal/serve_instance_qwen.py b/tools/modal/serve_instance_qwen.py index 61455d5b..df06a530 100644 --- a/tools/modal/serve_instance_qwen.py +++ b/tools/modal/serve_instance_qwen.py @@ -1,6 +1,8 @@ -import modal import os +import modal + + # -------- # Get config from environment variables # -------- diff --git a/tools/prompt_opt_dspy.py b/tools/prompt_opt_dspy.py index af0a90a7..c9f305c8 100644 --- a/tools/prompt_opt_dspy.py +++ b/tools/prompt_opt_dspy.py @@ -1,15 +1,13 @@ #!/usr/bin/env python3 import argparse import json -import os import re import shutil import subprocess import sys -import time from datetime import datetime from pathlib import Path -from typing import Any, Dict, List, Tuple, Optional +from typing import Any, Dict, List, Optional, Tuple # Optional DSPy import with friendly error try: diff --git a/tools/serving/api_cost_calculator.py b/tools/serving/api_cost_calculator.py index 455659cd..093fbea4 100644 --- a/tools/serving/api_cost_calculator.py +++ b/tools/serving/api_cost_calculator.py @@ -2,19 +2,18 @@ Costs dictionary and utility tool for counting tokens """ -import os -import tiktoken -import anthropic -from typing import Union, List, Dict -from .constants import TOKEN_COSTS -from decimal import Decimal import logging -from PIL import Image import math -import google.generativeai as genai import os +from decimal import Decimal +from typing import Dict, List, Union - +import anthropic +import google.generativeai as genai +import tiktoken +from PIL import Image + +from .constants import TOKEN_COSTS logger = logging.getLogger(__name__) @@ -357,7 +356,7 @@ def count_image_tokens(image_path: str, model: str): elif any(model.startswith(prefix) for prefix in ["claude"]): # Check if image needs to be resized (Claude limits) if width > 8000 or height > 8000: - logger.warning(f"Image exceeds Claude's maximum size of 8000x8000. It will be rejected or resized.") + logger.warning("Image exceeds Claude's maximum size of 8000x8000. It will be rejected or resized.") # If dimensions exceed 1568 on either side, it will be resized by Claude if width > 1568 or height > 1568: diff --git a/tools/serving/api_manager.py b/tools/serving/api_manager.py index cff9c5bd..1a288dba 100644 --- a/tools/serving/api_manager.py +++ b/tools/serving/api_manager.py @@ -8,59 +8,54 @@ 4. Store inputs and outputs in JSON format """ -import os +import base64 +import datetime import json -import time import logging -import datetime -import base64 +import os +import time from decimal import Decimal -from typing import Dict, List, Optional, Tuple, Union, Any +from typing import Any, Dict, List, Optional, Tuple, Union + +# Import cost calculator utilities +from .api_cost_calculator import ( + calculate_all_costs_and_tokens, + calculate_cost_by_tokens, + count_image_tokens, +) # Import API providers from .api_providers import ( anthropic_completion, - anthropic_text_completion, anthropic_multiimage_completion, - openai_completion, - openai_text_completion, - openai_multiimage_completion, + anthropic_text_completion, + deepseek_text_reasoning_completion, gemini_completion, - gemini_text_completion, gemini_multiimage_completion, - together_ai_completion, - together_ai_text_completion, - together_ai_multiimage_completion, - deepseek_text_reasoning_completion, - xai_grok_text_completion, - vllm_text_completion, - vllm_completion, - vllm_multiimage_completion, - modal_vllm_text_completion, + gemini_text_completion, + longcat_completion, + longcat_multiimage_completion, + longcat_text_completion, modal_vllm_completion, modal_vllm_multiimage_completion, - moonshot_text_completion, + modal_vllm_text_completion, moonshot_completion, moonshot_multiimage_completion, - stepfun_text_completion, + moonshot_text_completion, + openai_completion, + openai_multiimage_completion, + openai_text_completion, stepfun_completion, stepfun_multiimage_completion, + stepfun_text_completion, + together_ai_completion, + together_ai_multiimage_completion, + together_ai_text_completion, + vllm_completion, + vllm_multiimage_completion, + vllm_text_completion, + xai_grok_text_completion, zai_text_completion, - longcat_text_completion, - longcat_completion, - longcat_multiimage_completion -) - -# Import cost calculator utilities -from .api_cost_calculator import ( - calculate_all_costs_and_tokens, - count_message_tokens, - count_string_tokens, - count_image_tokens, - calculate_cost_by_tokens, - calculate_prompt_cost, - calculate_completion_cost, - calculate_image_cost, ) # Configure logging diff --git a/tools/serving/api_providers.py b/tools/serving/api_providers.py index 770dad93..0dbb0b5e 100644 --- a/tools/serving/api_providers.py +++ b/tools/serving/api_providers.py @@ -1,27 +1,21 @@ +import functools import os import random -import random import time -import functools -import httpx +from typing import List -from openai import OpenAI -from openai import RateLimitError, APITimeoutError, APIConnectionError, APIStatusError, BadRequestError import anthropic +import google.api_core.exceptions import google.generativeai as genai +import grpc +import httpx +import requests from google.generativeai import types -import google.api_core.exceptions +from openai import APIConnectionError, APIStatusError, APITimeoutError, BadRequestError, OpenAI, RateLimitError from together import Together - from zai import ZaiClient - -import requests -import grpc - -from typing import Optional, List, Any - def estimate_token_count(text: str) -> int: """ Rough estimation of token count for text. @@ -30,9 +24,7 @@ def estimate_token_count(text: str) -> int: if not text: return 0 return len(text) // 4 -import grpc -from typing import Optional, List, Any def estimate_token_count(text: str) -> int: """ @@ -428,7 +420,6 @@ def anthropic_multiimage_completion(system_prompt, model_name, prompt, list_cont return generated_str -import httpx _original_headers_init = httpx.Headers.__init__ @@ -651,8 +642,7 @@ def deepseek_text_reasoning_completion(system_prompt, model_name, prompt, token_ def xai_grok_text_completion(system_prompt, model_name, prompt, reasoning_effort="high", token_limit=30000, temperature=1): print(f"XAI Grok text API call: model={model_name}, reasoning_effort={reasoning_effort}") from xai_sdk import Client - from xai_sdk.chat import user, system - import grpc + from xai_sdk.chat import system, user client = Client( api_host="api.x.ai", @@ -660,8 +650,6 @@ def xai_grok_text_completion(system_prompt, model_name, prompt, reasoning_effort ) from xai_sdk import Client - from xai_sdk.chat import user, system - import grpc client = Client( api_host="api.x.ai", @@ -1203,7 +1191,6 @@ def parse_modal_model_name(modal_model_name: str) -> str: return modal_model_name[len("modal-"):] return modal_model_name -from openai import OpenAI def modal_vllm_text_completion( system_prompt: str, diff --git a/tools/serving/constants.py b/tools/serving/constants.py index 08d13258..41d52a98 100644 --- a/tools/serving/constants.py +++ b/tools/serving/constants.py @@ -1,8 +1,9 @@ -import os -import json -import aiohttp import asyncio +import json import logging +import os + +import aiohttp logger = logging.getLogger(__name__) diff --git a/tools/utils.py b/tools/utils.py index ec03565a..4d672f38 100644 --- a/tools/utils.py +++ b/tools/utils.py @@ -4,10 +4,12 @@ 2. Drawing coordinate grids on images """ -import cv2 import os + +import cv2 import numpy as np + def scale_image_up(image_path, maximum_scale=1500): """ Scales an image up to a maximum dimension while maintaining aspect ratio.