Skip to content

Commit 2260e3c

Browse files
fix: pick the token-limit parameter by model capability too
The four Chat Completions agents send `max_tokens` unconditionally. Every gpt-5 model rejects it: "Unsupported parameter: 'max_tokens' is not supported with this model. Use 'max_completion_tokens' instead." So even with the reasoning_effort gate corrected, these agents could not target any modern OpenAI reasoning model, only Fireworks-served models and gpt-4o. Select the parameter name from the same capability test, and fold the two copies of that test into one `_is_reasoning_model` helper per agent so they cannot drift apart. browsecomp-plus's reasoning_effort check moves onto the helper as well; it had the same provider-shaped gate as the other three. Verified live against the configured Azure endpoint, sending exactly the shapes the patched agents now build: gpt-4o ['max_tokens'] 200 gpt-5.4-mini-2026-03-17 ['max_completion_tokens','reasoning_effort'] 200 and the predicate classifies the suite's own targets correctly: `fireworks_ai/deepseek-v4-flash` and `fireworks_ai/gpt-oss-120b` are both non-reasoning, so the default configuration keeps the legacy shape and is unaffected. gaia and swe-bench-pro are untouched here: they use the Responses API, whose `max_output_tokens` has no such split. Refs #51. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 521c34e commit 2260e3c

4 files changed

Lines changed: 85 additions & 25 deletions

File tree

  • harness-engineering-bench
    • browsecomp-plus/baseline/target/src/browsecomp_plus_agent
    • officeqa/baseline/target/src/officeqa_agent
    • swe-atlas-qna/baseline/target/src/atlas_agent
    • tau3/baseline/target/src/tau3_agent

harness-engineering-bench/browsecomp-plus/baseline/target/src/browsecomp_plus_agent/agent.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@
1111
from harbor.models.agent.context import AgentContext
1212
from openai import AsyncOpenAI
1313

14+
def _is_reasoning_model(model: str) -> bool:
15+
"""Whether `model` is an OpenAI reasoning model.
16+
17+
Capability, not provider: Azure gpt-4o is not Fireworks yet still rejects
18+
reasoning_effort, and every gpt-5 model rejects max_tokens. Fireworks-served
19+
open models match none of these prefixes, so they keep the legacy shape.
20+
"""
21+
name = model.lower()
22+
return name.startswith(("gpt-5", "o1", "o3", "o4")) or "codex" in name
23+
1424
MAX_TURNS = 32
1525
MAX_TOOL_OUTPUT_CHARS = 40_000
1626

@@ -158,16 +168,24 @@ def _usage_value(value: Any, name: str) -> int:
158168
def _completion_kwargs(
159169
self, messages: list[dict[str, Any]], *, tools: bool = True
160170
) -> dict[str, Any]:
171+
# Reasoning models replaced max_tokens with max_completion_tokens and
172+
# reject the old name outright ("Unsupported parameter: 'max_tokens'
173+
# is not supported with this model"). Same capability test as the
174+
# reasoning_effort gate below, so the two stay consistent.
175+
_token_limit_key = (
176+
"max_completion_tokens"
177+
if _is_reasoning_model(self._api_model)
178+
else "max_tokens"
179+
)
161180
kwargs: dict[str, Any] = {
162181
"model": self._api_model,
163182
"messages": messages,
164-
"max_tokens": 12_000,
165183
}
184+
kwargs[_token_limit_key] = 12_000
166185
if tools:
167186
kwargs["tools"] = TOOLS
168-
# OpenAI reasoning models accept reasoning_effort; other providers
169-
# (e.g. Fireworks-served open models) reject it.
170-
if "fireworks" not in self._api_model:
187+
# Capability, not provider: see _is_reasoning_model.
188+
if _is_reasoning_model(self._api_model):
171189
kwargs["reasoning_effort"] = "medium"
172190
return kwargs
173191

harness-engineering-bench/officeqa/baseline/target/src/officeqa_agent/agent.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,16 @@
1313
from harbor.models.agent.context import AgentContext
1414
from openai import AsyncOpenAI
1515

16+
def _is_reasoning_model(model: str) -> bool:
17+
"""Whether `model` is an OpenAI reasoning model.
18+
19+
Capability, not provider: Azure gpt-4o is not Fireworks yet still rejects
20+
reasoning_effort, and every gpt-5 model rejects max_tokens. Fireworks-served
21+
open models match none of these prefixes, so they keep the legacy shape.
22+
"""
23+
name = model.lower()
24+
return name.startswith(("gpt-5", "o1", "o3", "o4")) or "codex" in name
25+
1626
MAX_TURNS = 24
1727
MAX_TOOL_OUTPUT_CHARS = 20_000
1828
MAX_IMAGE_BYTES = 20 * 1024 * 1024
@@ -172,19 +182,23 @@ def _usage_value(value: Any, name: str) -> int:
172182
def _completion_kwargs(
173183
self, messages: list[dict[str, Any]], *, tools: bool = True
174184
) -> dict[str, Any]:
185+
# Reasoning models replaced max_tokens with max_completion_tokens and
186+
# reject the old name outright ("Unsupported parameter: 'max_tokens'
187+
# is not supported with this model"). Same capability test as the
188+
# reasoning_effort gate below, so the two stay consistent.
189+
_token_limit_key = (
190+
"max_completion_tokens"
191+
if _is_reasoning_model(self._api_model)
192+
else "max_tokens"
193+
)
175194
kwargs: dict[str, Any] = {
176195
"model": self._api_model,
177196
"messages": messages,
178-
"max_tokens": 8000,
179197
}
198+
kwargs[_token_limit_key] = 8000
180199
if tools:
181200
kwargs["tools"] = TOOLS
182-
# Only reasoning-capable models accept reasoning_effort. A provider
183-
# check is not sufficient: Azure gpt-4o is not Fireworks and still
184-
# rejects it with "Unrecognized request argument supplied:
185-
# reasoning_effort".
186-
_model = self._api_model.lower()
187-
if _model.startswith(("gpt-5", "o1", "o3", "o4")) or "codex" in _model:
201+
if _is_reasoning_model(self._api_model):
188202
kwargs["reasoning_effort"] = "medium"
189203
# parallel_tool_calls is a separate axis: Fireworks-served models reject
190204
# it, but gpt-4o supports it, so this one stays a provider check.

harness-engineering-bench/swe-atlas-qna/baseline/target/src/atlas_agent/agent.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@
1111
from harbor.models.agent.context import AgentContext
1212
from openai import AsyncOpenAI
1313

14+
def _is_reasoning_model(model: str) -> bool:
15+
"""Whether `model` is an OpenAI reasoning model.
16+
17+
Capability, not provider: Azure gpt-4o is not Fireworks yet still rejects
18+
reasoning_effort, and every gpt-5 model rejects max_tokens. Fireworks-served
19+
open models match none of these prefixes, so they keep the legacy shape.
20+
"""
21+
name = model.lower()
22+
return name.startswith(("gpt-5", "o1", "o3", "o4")) or "codex" in name
23+
1424
MAX_TURNS = 40
1525
MAX_TOOL_OUTPUT_CHARS = 30_000
1626

@@ -152,19 +162,23 @@ def _usage_value(value: Any, name: str) -> int:
152162
def _completion_kwargs(
153163
self, messages: list[dict[str, Any]], *, tools: bool = True
154164
) -> dict[str, Any]:
165+
# Reasoning models replaced max_tokens with max_completion_tokens and
166+
# reject the old name outright ("Unsupported parameter: 'max_tokens'
167+
# is not supported with this model"). Same capability test as the
168+
# reasoning_effort gate below, so the two stay consistent.
169+
_token_limit_key = (
170+
"max_completion_tokens"
171+
if _is_reasoning_model(self._api_model)
172+
else "max_tokens"
173+
)
155174
kwargs: dict[str, Any] = {
156175
"model": self._api_model,
157176
"messages": messages,
158-
"max_tokens": 12_000,
159177
}
178+
kwargs[_token_limit_key] = 12_000
160179
if tools:
161180
kwargs["tools"] = TOOLS
162-
# Only reasoning-capable models accept reasoning_effort. A provider
163-
# check is not sufficient: Azure gpt-4o is not Fireworks and still
164-
# rejects it with "Unrecognized request argument supplied:
165-
# reasoning_effort".
166-
_model = self._api_model.lower()
167-
if _model.startswith(("gpt-5", "o1", "o3", "o4")) or "codex" in _model:
181+
if _is_reasoning_model(self._api_model):
168182
kwargs["reasoning_effort"] = "high"
169183
return kwargs
170184

harness-engineering-bench/tau3/baseline/target/src/tau3_agent/agent.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@
2727
from harbor.models.agent.context import AgentContext
2828
from openai import AsyncOpenAI
2929

30+
def _is_reasoning_model(model: str) -> bool:
31+
"""Whether `model` is an OpenAI reasoning model.
32+
33+
Capability, not provider: Azure gpt-4o is not Fireworks yet still rejects
34+
reasoning_effort, and every gpt-5 model rejects max_tokens. Fireworks-served
35+
open models match none of these prefixes, so they keep the legacy shape.
36+
"""
37+
name = model.lower()
38+
return name.startswith(("gpt-5", "o1", "o3", "o4")) or "codex" in name
39+
3040
MAX_TURNS = 80
3141
MAX_TOOL_OUTPUT_CHARS = 30_000
3242
PROTOCOL_VERSION = "2025-06-18"
@@ -309,18 +319,22 @@ async def run(
309319

310320
for turn in range(1, MAX_TURNS + 1):
311321
turns = turn
322+
# Reasoning models replaced max_tokens with max_completion_tokens and
323+
# reject the old name outright ("Unsupported parameter: 'max_tokens'
324+
# is not supported with this model"). Same capability test as the
325+
# reasoning_effort gate below, so the two stay consistent.
326+
_token_limit_key = (
327+
"max_completion_tokens"
328+
if _is_reasoning_model(self._api_model)
329+
else "max_tokens"
330+
)
312331
kwargs: dict[str, Any] = {
313332
"model": self._api_model,
314333
"messages": messages,
315334
"tools": openai_tools,
316-
"max_tokens": 8_000,
317335
}
318-
# Only reasoning-capable models accept reasoning_effort. A provider
319-
# check is not sufficient: Azure gpt-4o is not Fireworks and still
320-
# rejects it with "Unrecognized request argument supplied:
321-
# reasoning_effort".
322-
_model = self._api_model.lower()
323-
if _model.startswith(("gpt-5", "o1", "o3", "o4")) or "codex" in _model:
336+
kwargs[_token_limit_key] = 8_000
337+
if _is_reasoning_model(self._api_model):
324338
kwargs["reasoning_effort"] = "medium"
325339
response = await client.chat.completions.create(**kwargs)
326340
usage = response.usage

0 commit comments

Comments
 (0)