Skip to content

Commit b833c70

Browse files
fix: strip temperature/top_p for reasoning models in AgentBuilder
Reasoning models (o1, o3, o4, gpt-5.x) reject custom temperature and top_p values. The old agent-framework beta silently stripped these, but 1.1.1+ passes them through causing 400 errors. This fix auto-detects the model name from the client and removes unsupported params before building ChatOptions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 96df974 commit b833c70

2 files changed

Lines changed: 96 additions & 0 deletions

File tree

src/ContentProcessor/src/libs/agent_framework/agent_builder.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
Azure OpenAI models with structured output.
99
"""
1010

11+
import logging
1112
from collections.abc import Callable, MutableMapping, Sequence
1213
from typing import Any, Literal
1314

@@ -27,6 +28,47 @@
2728

2829
from .agent_info import AgentInfo
2930

31+
logger = logging.getLogger(__name__)
32+
33+
# Reasoning models that do not support custom temperature/top_p values.
34+
_REASONING_MODEL_PREFIXES = ("o1", "o3", "o4", "gpt-5")
35+
36+
37+
def _is_reasoning_model(model_name: str) -> bool:
38+
"""Check if a model is a reasoning model based on its deployment name."""
39+
name = model_name.lower()
40+
return any(name.startswith(prefix) for prefix in _REASONING_MODEL_PREFIXES)
41+
42+
43+
def _resolve_model_name(client: Any, model_id: str | None = None) -> str | None:
44+
"""Extract model/deployment name from the client or explicit model_id."""
45+
if model_id:
46+
return model_id
47+
for attr in ("model", "_model", "model_id"):
48+
val = getattr(client, attr, None)
49+
if isinstance(val, str):
50+
return val
51+
return None
52+
53+
54+
def _strip_unsupported_reasoning_params(
55+
options: dict[str, Any], model_name: str | None
56+
) -> dict[str, Any]:
57+
"""Remove temperature and top_p for reasoning models that don't support them."""
58+
if model_name and _is_reasoning_model(model_name):
59+
removed = []
60+
for param in ("temperature", "top_p"):
61+
if param in options:
62+
del options[param]
63+
removed.append(param)
64+
if removed:
65+
logger.info(
66+
"Stripped unsupported params %s for reasoning model '%s'",
67+
removed,
68+
model_name,
69+
)
70+
return options
71+
3072

3173
class AgentBuilder:
3274
"""Fluent builder for creating ChatAgent instances with a chainable API.
@@ -483,6 +525,9 @@ def build(self) -> Agent:
483525
if self._additional_chat_options:
484526
options.update(self._additional_chat_options)
485527

528+
model_name = _resolve_model_name(self._chat_client, self._model_id)
529+
_strip_unsupported_reasoning_params(options, model_name)
530+
486531
default_options: ChatOptions | None = ChatOptions(**options) if options else None
487532

488533
return Agent(
@@ -821,6 +866,9 @@ def create_agent(
821866
if additional_chat_options:
822867
options.update(additional_chat_options)
823868

869+
model_name = _resolve_model_name(chat_client, model_id)
870+
_strip_unsupported_reasoning_params(options, model_name)
871+
824872
default_options: ChatOptions | None = ChatOptions(**options) if options else None
825873

826874
return Agent(

src/ContentProcessorWorkflow/src/libs/agent_framework/agent_builder.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
- Provider-specific options: ``additional_chat_options`` dict.
3131
"""
3232

33+
import logging
3334
from collections.abc import Callable, MutableMapping, Sequence
3435
from typing import Any, Literal
3536

@@ -48,6 +49,47 @@
4849
from libs.agent_framework.agent_info import AgentInfo
4950
from utils.credential_util import get_bearer_token_provider
5051

52+
logger = logging.getLogger(__name__)
53+
54+
# Reasoning models that do not support custom temperature/top_p values.
55+
_REASONING_MODEL_PREFIXES = ("o1", "o3", "o4", "gpt-5")
56+
57+
58+
def _is_reasoning_model(model_name: str) -> bool:
59+
"""Check if a model is a reasoning model based on its deployment name."""
60+
name = model_name.lower()
61+
return any(name.startswith(prefix) for prefix in _REASONING_MODEL_PREFIXES)
62+
63+
64+
def _resolve_model_name(client: Any, model_id: str | None = None) -> str | None:
65+
"""Extract model/deployment name from the client or explicit model_id."""
66+
if model_id:
67+
return model_id
68+
for attr in ("model", "_model", "model_id"):
69+
val = getattr(client, attr, None)
70+
if isinstance(val, str):
71+
return val
72+
return None
73+
74+
75+
def _strip_unsupported_reasoning_params(
76+
options: dict[str, Any], model_name: str | None
77+
) -> dict[str, Any]:
78+
"""Remove temperature and top_p for reasoning models that don't support them."""
79+
if model_name and _is_reasoning_model(model_name):
80+
removed = []
81+
for param in ("temperature", "top_p"):
82+
if param in options:
83+
del options[param]
84+
removed.append(param)
85+
if removed:
86+
logger.info(
87+
"Stripped unsupported params %s for reasoning model '%s'",
88+
removed,
89+
model_name,
90+
)
91+
return options
92+
5193

5294
class AgentBuilder:
5395
"""Fluent builder for creating ChatAgent instances with a chainable API.
@@ -518,6 +560,9 @@ def build(self) -> Agent:
518560
if self._additional_chat_options:
519561
options.update(self._additional_chat_options)
520562

563+
model_name = _resolve_model_name(self._chat_client, self._model_id)
564+
_strip_unsupported_reasoning_params(options, model_name)
565+
521566
default_options: ChatOptions | None = ChatOptions(**options) if options else None
522567

523568
return Agent(
@@ -869,6 +914,9 @@ def create_agent(
869914
if additional_chat_options:
870915
options.update(additional_chat_options)
871916

917+
model_name = _resolve_model_name(chat_client, model_id)
918+
_strip_unsupported_reasoning_params(options, model_name)
919+
872920
default_options: ChatOptions | None = ChatOptions(**options) if options else None
873921

874922
return Agent(

0 commit comments

Comments
 (0)