Merge branch 'main' into fix-issue-5344-quantization-guardrail

This commit is contained in:
Daniel Han 2026-05-15 06:50:53 -07:00 committed by GitHub
commit ee95f9a9a7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 72 additions and 2 deletions

View file

@ -29,6 +29,7 @@ logger = structlog.get_logger(__name__)
# still accept it. Match the 4-7 line specifically so we keep the knob
# live on every other Claude generation.
_ANTHROPIC_TOP_K_DEPRECATED = re.compile(r"^claude-(?:opus|sonnet|haiku)-4-7(?:[-.]|$)")
_OPENAI_REASONING_SUMMARY_UNSUPPORTED = re.compile(r"^o3(?:[-.]|$)")
class _AnthropicThinkingSpec(NamedTuple):
@ -1659,6 +1660,9 @@ class ExternalProviderClient:
# to wrap, and the chat reasoning panel stays blank. Always pair
# an explicit effort with summary except for the explicit "off"
# case (effort: "none"), where summaries are pointless.
summary_unsupported = bool(
_OPENAI_REASONING_SUMMARY_UNSUPPORTED.match(model.strip().lower())
)
if reasoning_effort in (
"minimal",
"low",
@ -1667,11 +1671,15 @@ class ExternalProviderClient:
"max",
"xhigh",
):
body["reasoning"] = {"effort": reasoning_effort, "summary": "auto"}
body["reasoning"] = {"effort": reasoning_effort}
if not summary_unsupported:
body["reasoning"]["summary"] = "auto"
elif reasoning_effort == "none" or enable_thinking is False:
body["reasoning"] = {"effort": "none"}
elif enable_thinking is True:
body["reasoning"] = {"effort": "medium", "summary": "auto"}
body["reasoning"] = {"effort": "medium"}
if not summary_unsupported:
body["reasoning"]["summary"] = "auto"
if instructions_parts:
body["instructions"] = "\n\n".join(instructions_parts)
if max_tokens is not None:

View file

@ -286,6 +286,68 @@ def test_responses_reasoning_effort_included_when_requested(monkeypatch):
assert captured["body"]["reasoning"] == {"effort": "high", "summary": "auto"}
def test_responses_reasoning_summary_omitted_for_o3(monkeypatch):
captured: dict = {}
def handler(request: httpx.Request) -> httpx.Response:
captured["body"] = json.loads(request.content.decode("utf-8"))
return httpx.Response(
200,
content = _responses_sse([{"type": "response.completed", "response": {}}]),
headers = {"content-type": "text/event-stream"},
)
_mock_http_client(monkeypatch, handler)
async def run():
client = _make_client()
async for _ in client._stream_openai_responses(
messages = [{"role": "user", "content": "hi"}],
model = "o3",
temperature = 0.7,
top_p = 0.95,
max_tokens = None,
enable_thinking = None,
reasoning_effort = "high",
):
pass
await client.close()
_drive(run())
assert captured["body"]["reasoning"] == {"effort": "high"}
def test_responses_reasoning_summary_omitted_for_o3_with_enable_thinking(monkeypatch):
captured: dict = {}
def handler(request: httpx.Request) -> httpx.Response:
captured["body"] = json.loads(request.content.decode("utf-8"))
return httpx.Response(
200,
content = _responses_sse([{"type": "response.completed", "response": {}}]),
headers = {"content-type": "text/event-stream"},
)
_mock_http_client(monkeypatch, handler)
async def run():
client = _make_client()
async for _ in client._stream_openai_responses(
messages = [{"role": "user", "content": "hi"}],
model = "o3",
temperature = 0.7,
top_p = 0.95,
max_tokens = None,
enable_thinking = True,
reasoning_effort = None,
):
pass
await client.close()
_drive(run())
assert captured["body"]["reasoning"] == {"effort": "medium"}
def test_responses_reasoning_effort_none_omits_summary(monkeypatch):
captured: dict = {}