Lower reasoning effort for recommended conversations, raise it for AI tasks

Recommended settings are resolved at runtime, so subentries without a
stored reasoning effort now use minimal for conversation (voice commands
stay snappy) and medium for AI tasks (quality over latency).

The efforts a model accepts differ per model, so the entity default only
applies to the recommended model, other models keep using low.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SNEGNPyUtLLDerutyVvE3F
This commit is contained in:
Claude
2026-07-25 19:03:58 +00:00
parent 0b705fbc40
commit fafcb67827
9 changed files with 69 additions and 8 deletions
@@ -55,6 +55,7 @@ from .const import (
LOGGER,
RECOMMENDED_AI_TASK_OPTIONS,
RECOMMENDED_CHAT_MODEL,
RECOMMENDED_CONVERSATION_REASONING_EFFORT,
RECOMMENDED_MAX_TOKENS,
RECOMMENDED_REASONING_EFFORT,
RECOMMENDED_REASONING_SUMMARY,
@@ -217,7 +218,10 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
if model.startswith(("o", "gpt-5")):
model_args["reasoning"] = {
"effort": conversation_subentry.data.get(
CONF_REASONING_EFFORT, RECOMMENDED_REASONING_EFFORT
CONF_REASONING_EFFORT,
RECOMMENDED_CONVERSATION_REASONING_EFFORT
if model == RECOMMENDED_CHAT_MODEL
else RECOMMENDED_REASONING_EFFORT,
)
}
@@ -16,6 +16,7 @@ from homeassistant.util.json import json_loads
from .const import (
CONF_CHAT_MODEL,
CONF_IMAGE_MODEL,
RECOMMENDED_AI_TASK_REASONING_EFFORT,
RECOMMENDED_CHAT_MODEL,
RECOMMENDED_IMAGE_MODEL,
UNSUPPORTED_IMAGE_MODELS,
@@ -52,6 +53,8 @@ class OpenAITaskEntity(
):
"""OpenAI AI Task entity."""
_recommended_reasoning_effort = RECOMMENDED_AI_TASK_REASONING_EFFORT
def __init__(self, entry: OpenAIConfigEntry, subentry: ConfigSubentry) -> None:
"""Initialize the entity."""
super().__init__(entry, subentry)
@@ -44,6 +44,8 @@ RECOMMENDED_IMAGE_MODEL = "gpt-image-2"
RECOMMENDED_MAX_TOKENS = 3000
RECOMMENDED_PRO_MODE = False
RECOMMENDED_REASONING_EFFORT = "low"
RECOMMENDED_CONVERSATION_REASONING_EFFORT = "minimal"
RECOMMENDED_AI_TASK_REASONING_EFFORT = "medium"
RECOMMENDED_STORE_RESPONSES = False
RECOMMENDED_REASONING_SUMMARY = "auto"
RECOMMENDED_SERVICE_TIER = "auto"
@@ -9,7 +9,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import OpenAIConfigEntry
from .const import DOMAIN
from .const import DOMAIN, RECOMMENDED_CONVERSATION_REASONING_EFFORT
from .entity import OpenAIBaseLLMEntity
# Max number of back and forth with the LLM to generate a response
@@ -39,6 +39,7 @@ class OpenAIConversationEntity(
"""OpenAI conversation agent."""
_attr_supports_streaming = True
_recommended_reasoning_effort = RECOMMENDED_CONVERSATION_REASONING_EFFORT
def __init__(self, entry: OpenAIConfigEntry, subentry: ConfigSubentry) -> None:
"""Initialize the agent."""
@@ -480,6 +480,8 @@ class OpenAIBaseLLMEntity(Entity):
_attr_has_entity_name = True
_attr_name: str | None = None
# Effort used in recommended mode, must be supported by RECOMMENDED_CHAT_MODEL
_recommended_reasoning_effort = RECOMMENDED_REASONING_EFFORT
def __init__(self, entry: OpenAIConfigEntry, subentry: ConfigSubentry) -> None:
"""Initialize the entity."""
@@ -523,10 +525,14 @@ class OpenAIBaseLLMEntity(Entity):
)
if model_args["model"].startswith(("o", "gpt-5")):
# Other models support a different set of efforts
recommended_effort = (
self._recommended_reasoning_effort
if model_args["model"] == RECOMMENDED_CHAT_MODEL
else RECOMMENDED_REASONING_EFFORT
)
reasoning: Reasoning = {
"effort": options.get(
CONF_REASONING_EFFORT, RECOMMENDED_REASONING_EFFORT
)
"effort": options.get(CONF_REASONING_EFFORT, recommended_effort)
if not model_args["model"].startswith("gpt-5-pro")
else "high", # GPT-5 pro only supports reasoning.effort: high
}
@@ -297,7 +297,7 @@
}),
])
# ---
# name: test_model_args[subentry_options0]
# name: test_model_args[pro_mode]
dict({
'include': list([
'reasoning.encrypted_content',
@@ -318,6 +318,25 @@
}),
})
# ---
# name: test_model_args[recommended]
dict({
'include': list([
'reasoning.encrypted_content',
]),
'max_output_tokens': 3000,
'model': 'gpt-5-nano',
'reasoning': dict({
'effort': 'minimal',
'summary': 'auto',
}),
'service_tier': 'auto',
'store': False,
'stream': True,
'text': dict({
'verbosity': 'medium',
}),
})
# ---
# name: test_web_search[False]
list([
dict({
@@ -68,6 +68,26 @@ async def test_generate_data(
assert mock_create_stream.call_args.kwargs["store"] is expected_store
@pytest.mark.usefixtures("mock_init_component", "mock_config_entry")
async def test_recommended_reasoning_effort(
hass: HomeAssistant,
mock_create_stream: AsyncMock,
) -> None:
"""Test AI Task reasons more than conversation with recommended settings."""
mock_create_stream.return_value = [
create_message_item(id="msg_A", text="The test data", output_index=0)
]
await ai_task.async_generate_data(
hass,
task_name="Test Task",
entity_id="ai_task.openai_ai_task",
instructions="Generate test data",
)
assert mock_create_stream.call_args.kwargs["reasoning"]["effort"] == "medium"
@pytest.mark.usefixtures("mock_init_component")
async def test_generate_structured_data(
hass: HomeAssistant,
@@ -821,7 +821,13 @@ async def test_flex_tier_retry(
@pytest.mark.parametrize(
"subentry_options", [{CONF_CHAT_MODEL: "gpt-5.6-sol", CONF_PRO_MODE: True}]
"subentry_options",
[
pytest.param(
{CONF_CHAT_MODEL: "gpt-5.6-sol", CONF_PRO_MODE: True}, id="pro_mode"
),
pytest.param({}, id="recommended"),
],
)
async def test_model_args(
hass: HomeAssistant,
@@ -429,7 +429,7 @@ async def test_generate_content_service(
service_data["config_entry"] = mock_config_entry.entry_id
expected_args["model"] = "gpt-5-nano"
expected_args["max_output_tokens"] = 3000
expected_args["reasoning"] = {"effort": "low"}
expected_args["reasoning"] = {"effort": "minimal"}
expected_args["user"] = None
expected_args["store"] = store_responses
expected_args["input"][0]["type"] = "message"