Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/static-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ jobs:
- name: Ruff format check
run: uv run --frozen ruff format --check .

- name: Pyright check
run: uv run --frozen pyright src/clawbench tests

- name: Build package
env:
UV_FROZEN: "true"
Expand Down
7 changes: 7 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,10 @@ repos:
- id: ruff-check
- id: ruff-format
args: [--check]
- repo: local
hooks:
- id: pyright
name: pyright
entry: uv run --frozen pyright src/clawbench tests
language: system
pass_filenames: false
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
### Changed
- More data are stored in the `run-meta.json` for better post-hoc analysis and reproducibility, including the hash of the configs, runtime info, and flags used.

### Fixed
- Fixed several compatibility issues on Windows platforms.

## [0.3.2] - 2026-05-15
### Added
- Added the logic to remove the `.log` files from the generated `data/` directory to remove noise.
Expand Down
9 changes: 9 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,19 @@ exclude = [
[tool.ruff]
target-version = "py311"

[tool.pyright]
include = ["src/clawbench", "tests"]
exclude = [
".venv",
"src/clawbench/runtime/extension-server",
"src/clawbench/runtime/harnesses",
]

[dependency-groups]
dev = [
"jsonschema>=4.26.0",
"pre-commit>=4.6.0",
"pyright>=1.1.407",
"pytest>=9.0.3",
"ruff>=0.15.12",
]
1 change: 1 addition & 0 deletions src/clawbench/runner/batch.py
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,7 @@ async def async_main(args: argparse.Namespace) -> int:

def on_signal() -> None:
nonlocal sigint_count
assert shutdown_event is not None
sigint_count += 1
shutdown_event.set()

Expand Down
55 changes: 49 additions & 6 deletions src/clawbench/tui.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,13 +384,55 @@ def load_cases(cases_dir_name: str = "test-cases") -> list[str]:
# ---------------------------------------------------------------------------


def _recommend_concurrent() -> int:
cpus = multiprocessing.cpu_count()
def _windows_physical_memory_gb() -> float | None:
try:
import ctypes
except ImportError:
return None

windll = getattr(ctypes, "windll", None)
if windll is None:
return None

class MEMORYSTATUSEX(ctypes.Structure):
_fields_ = [
("dwLength", ctypes.c_ulong),
("dwMemoryLoad", ctypes.c_ulong),
("ullTotalPhys", ctypes.c_ulonglong),
("ullAvailPhys", ctypes.c_ulonglong),
("ullTotalPageFile", ctypes.c_ulonglong),
("ullAvailPageFile", ctypes.c_ulonglong),
("ullTotalVirtual", ctypes.c_ulonglong),
("ullAvailVirtual", ctypes.c_ulonglong),
("ullAvailExtendedVirtual", ctypes.c_ulonglong),
]

status = MEMORYSTATUSEX()
status.dwLength = ctypes.sizeof(status)
try:
ok = windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(status))
except (AttributeError, OSError):
return None
if not ok:
return None
return status.ullTotalPhys / (1024**3)


def _physical_memory_gb() -> float:
if platform.system() == "Windows":
mem_gb = _windows_physical_memory_gb()
if mem_gb is not None:
return mem_gb
try:
mem_bytes = os.sysconf("SC_PAGE_SIZE") * os.sysconf("SC_PHYS_PAGES")
mem_gb = mem_bytes / (1024**3)
except (ValueError, OSError):
mem_gb = 8
return mem_bytes / (1024**3)
except (AttributeError, ValueError, OSError):
return 8


def _recommend_concurrent() -> int:
cpus = multiprocessing.cpu_count()
mem_gb = _physical_memory_gb()
by_cpu = cpus // 2
by_ram = int(mem_gb // 2)
recommended = max(1, min(by_cpu, by_ram))
Expand Down Expand Up @@ -1270,7 +1312,7 @@ def _run_streamed(cmd: list[str], *, status_msg: str) -> int:
return rc


def _fix_engine(engine: str, status: str, detail: str) -> bool:
def _fix_engine(engine: str | None, status: str, detail: str) -> bool:
"""Show an actionable panel for the engine problem and offer a fix.

Returns True if the engine is now usable, False otherwise. Safe to
Expand Down Expand Up @@ -1530,6 +1572,7 @@ def main() -> None:
console.print()
console.print("[bold]Welcome to ClawBench.[/]")
theme = _pick_theme()
assert theme is not None
STYLE = _make_style(theme)
# Apple HIG: Indigo for headers, Blue for inline accents
if theme == "light":
Expand Down
42 changes: 42 additions & 0 deletions tests/test_tui_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

import subprocess
import sys
import types
from pathlib import Path
from typing import Any

import pytest

Expand Down Expand Up @@ -242,6 +244,46 @@ def test_tui_recommend_concurrent_returns_positive_value(
assert tui._recommend_concurrent() >= 1


def test_tui_recommend_concurrent_uses_windows_memory(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setattr(tui.platform, "system", lambda: "Windows")
monkeypatch.setattr(tui.multiprocessing, "cpu_count", lambda: 16)
monkeypatch.setattr(tui, "_windows_physical_memory_gb", lambda: 4)

assert tui._recommend_concurrent() == 2


def test_tui_windows_physical_memory_uses_global_memory_status(
monkeypatch: pytest.MonkeyPatch,
) -> None:
class Kernel32:
def GlobalMemoryStatusEx(self, status: Any) -> int:
status.ullTotalPhys = 12 * 1024**3
return 1

fake_ctypes: Any = types.ModuleType("ctypes")
fake_ctypes.Structure = object
fake_ctypes.c_ulong = object()
fake_ctypes.c_ulonglong = object()
fake_ctypes.sizeof = lambda _status: 64
fake_ctypes.byref = lambda status: status
fake_ctypes.windll = types.SimpleNamespace(kernel32=Kernel32())
monkeypatch.setitem(sys.modules, "ctypes", fake_ctypes)

assert tui._windows_physical_memory_gb() == 12


def test_tui_physical_memory_falls_back_when_unavailable(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setattr(tui.platform, "system", lambda: "Windows")
monkeypatch.setattr(tui, "_windows_physical_memory_gb", lambda: None)
monkeypatch.delattr(tui.os, "sysconf", raising=False)

assert tui._physical_memory_gb() == 8


def test_tui_main_single_run_flow_builds_runner_command(
monkeypatch: pytest.MonkeyPatch,
) -> None:
Expand Down
15 changes: 15 additions & 0 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading