Skip to content
Open
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
24 changes: 23 additions & 1 deletion src/evolve/integrations/harbor/miniswe_candidate.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,23 @@ def _reasoning_effort():
return effort


def _max_output_tokens():
raw = os.environ.get("MINISWE_MAX_OUTPUT_LIMIT", "").strip()
if not raw:
return None
try:
value = int(raw)
except ValueError as error:
raise ValueError(
f"Invalid MINISWE_MAX_OUTPUT_LIMIT={raw!r}; expected a positive integer"
) from error
if value <= 0:
raise ValueError(
f"Invalid MINISWE_MAX_OUTPUT_LIMIT={raw!r}; expected a positive integer"
)
return value


def build_model(config):
model_name = os.environ["MSWEA_MODEL_NAME"]
effort = _reasoning_effort()
Expand All @@ -78,7 +95,11 @@ def build_model(config):

if model_name.startswith("openai/"):
nested_kwargs = dict(model_kwargs.get("model_kwargs") or {})
nested_kwargs.setdefault("max_output_tokens", 64_000)
output_limit = _max_output_tokens()
if output_limit is None:
nested_kwargs.setdefault("max_output_tokens", 64_000)
else:
nested_kwargs["max_output_tokens"] = output_limit
nested_kwargs.pop("reasoning_effort", None)
if effort is not None:
nested_kwargs["reasoning"] = {"effort": effort}
Expand Down Expand Up @@ -519,6 +540,7 @@ def _source_env(self) -> dict[str, str]:
for name in (
"MINISWE_STEP_LIMIT",
"MINISWE_COST_LIMIT",
"MINISWE_MAX_OUTPUT_LIMIT",
"MINISWE_ENV_TIMEOUT",
"MINISWE_REASONING_EFFORT",
):
Expand Down
31 changes: 31 additions & 0 deletions tests/test_miniswe_harbor_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,16 @@ def test_miniswe_wrapper_forwards_reasoning_effort(adapter_path: Path, monkeypat
assert "MINISWE_REASONING_EFFORT" not in module.MiniSweSourceAgent()._source_env()


def test_miniswe_wrapper_forwards_max_output_limit(adapter_path: Path, monkeypatch) -> None:
_install_fake_harbor(monkeypatch)
module = _load(adapter_path)
monkeypatch.setenv("MINISWE_MAX_OUTPUT_LIMIT", "10000")

source_env = module.MiniSweSourceAgent()._source_env()

assert source_env["MINISWE_MAX_OUTPUT_LIMIT"] == "10000"


def test_miniswe_wrapper_source_environment_contains_only_strings(adapter_path: Path, monkeypatch) -> None:
_install_fake_harbor(monkeypatch)
module = _load(adapter_path)
Expand Down Expand Up @@ -257,6 +267,27 @@ def test_miniswe_wrapper_preserves_explicit_responses_output_budget(adapter_path
assert model.kwargs["model_kwargs"]["max_output_tokens"] == 12_345


def test_miniswe_wrapper_runtime_output_limit_overrides_candidate_config(adapter_path: Path, monkeypatch) -> None:
_, build_model, (_, FakeLitellmResponseModel) = _load_model_factory(adapter_path, monkeypatch)
monkeypatch.setenv("MSWEA_MODEL_NAME", "openai/gpt-5.4")
monkeypatch.setenv("MINISWE_MAX_OUTPUT_LIMIT", "10000")

model = build_model({"model": {"model_kwargs": {"max_output_tokens": 64_000}}})

assert type(model) is FakeLitellmResponseModel
assert model.kwargs["model_kwargs"]["max_output_tokens"] == 10_000


@pytest.mark.parametrize("value", ["0", "-1", "invalid"])
def test_miniswe_wrapper_rejects_invalid_runtime_output_limit(adapter_path: Path, monkeypatch, value: str) -> None:
_, build_model, _ = _load_model_factory(adapter_path, monkeypatch)
monkeypatch.setenv("MSWEA_MODEL_NAME", "openai/gpt-5.4")
monkeypatch.setenv("MINISWE_MAX_OUTPUT_LIMIT", value)

with pytest.raises(ValueError, match="expected a positive integer"):
build_model({"model": {}})


def test_miniswe_wrapper_uses_responses_without_openai_reasoning(adapter_path: Path, monkeypatch) -> None:
_, build_model, (FakeLitellmModel, FakeLitellmResponseModel) = _load_model_factory(adapter_path, monkeypatch)
monkeypatch.setenv("MSWEA_MODEL_NAME", "openai/gpt-5.4")
Expand Down
Loading