mirror of
https://github.com/home-assistant/core.git
synced 2026-09-25 17:04:04 -04:00
Add GPT-6 Astra support (#181693)
This commit is contained in:
@@ -423,7 +423,7 @@ class OpenAISubentryFlowHandler(ConfigSubentryFlow):
|
||||
elif CONF_REASONING_EFFORT in options:
|
||||
options.pop(CONF_REASONING_EFFORT)
|
||||
|
||||
if model.startswith("gpt-5.6"):
|
||||
if model.startswith(("gpt-5.6", "gpt-6")):
|
||||
step_schema.update(
|
||||
{
|
||||
vol.Optional(
|
||||
@@ -435,7 +435,7 @@ class OpenAISubentryFlowHandler(ConfigSubentryFlow):
|
||||
elif CONF_PRO_MODE in options:
|
||||
options.pop(CONF_PRO_MODE)
|
||||
|
||||
if model.startswith("gpt-5"):
|
||||
if model.startswith(("gpt-5", "gpt-6")):
|
||||
step_schema.update(
|
||||
{
|
||||
vol.Optional(
|
||||
@@ -453,7 +453,7 @@ class OpenAISubentryFlowHandler(ConfigSubentryFlow):
|
||||
elif CONF_VERBOSITY in options:
|
||||
options.pop(CONF_VERBOSITY)
|
||||
|
||||
if model.startswith(("o", "gpt-5")):
|
||||
if model.startswith(("o", "gpt-5", "gpt-6")):
|
||||
reasoning_summary_options = ["off", "auto", "concise", "detailed"]
|
||||
if model.startswith("o"):
|
||||
reasoning_summary_options.remove("concise")
|
||||
@@ -602,10 +602,13 @@ class OpenAISubentryFlowHandler(ConfigSubentryFlow):
|
||||
|
||||
def _get_reasoning_options(self, model: str) -> list[str]:
|
||||
"""Get reasoning effort options based on model."""
|
||||
if not model.startswith(("o", "gpt-5")) or model.startswith("gpt-5-pro"):
|
||||
if not model.startswith(("o", "gpt-5", "gpt-6")) or model.startswith(
|
||||
"gpt-5-pro"
|
||||
):
|
||||
return []
|
||||
|
||||
models_reasoning_map: dict[str | tuple[str, ...], list[str]] = {
|
||||
"gpt-6": ["low", "medium", "high", "xhigh", "max"],
|
||||
"gpt-5.6": ["none", "low", "medium", "high", "xhigh", "max"],
|
||||
("gpt-5.2-pro", "gpt-5.4-pro", "gpt-5.5-pro"): ["medium", "high", "xhigh"],
|
||||
("gpt-5.2", "gpt-5.3", "gpt-5.4", "gpt-5.5"): [
|
||||
|
||||
@@ -523,7 +523,7 @@ class OpenAIBaseLLMEntity(Entity):
|
||||
stream=True,
|
||||
)
|
||||
|
||||
if model_args["model"].startswith(("o", "gpt-5")):
|
||||
if model_args["model"].startswith(("o", "gpt-5", "gpt-6")):
|
||||
reasoning: Reasoning = {
|
||||
"effort": options.get(
|
||||
CONF_REASONING_EFFORT, RECOMMENDED_REASONING_EFFORT
|
||||
@@ -545,7 +545,7 @@ class OpenAIBaseLLMEntity(Entity):
|
||||
model_args["include"] = ["reasoning.encrypted_content"]
|
||||
|
||||
if (
|
||||
not model_args["model"].startswith("gpt-5")
|
||||
not model_args["model"].startswith(("gpt-5", "gpt-6"))
|
||||
or model_args["reasoning"]["effort"] == "none" # type: ignore[index]
|
||||
):
|
||||
model_args["top_p"] = options.get(CONF_TOP_P, RECOMMENDED_TOP_P)
|
||||
@@ -553,7 +553,7 @@ class OpenAIBaseLLMEntity(Entity):
|
||||
CONF_TEMPERATURE, RECOMMENDED_TEMPERATURE
|
||||
)
|
||||
|
||||
if model_args["model"].startswith("gpt-5"):
|
||||
if model_args["model"].startswith(("gpt-5", "gpt-6")):
|
||||
model_args["text"] = {
|
||||
"verbosity": options.get(CONF_VERBOSITY, RECOMMENDED_VERBOSITY)
|
||||
}
|
||||
@@ -561,7 +561,10 @@ class OpenAIBaseLLMEntity(Entity):
|
||||
if not model_args["model"].startswith(
|
||||
tuple(UNSUPPORTED_EXTENDED_CACHE_RETENTION_MODELS)
|
||||
):
|
||||
model_args["prompt_cache_retention"] = "24h"
|
||||
if model_args["model"].startswith(("gpt-5.6", "gpt-6")):
|
||||
model_args["prompt_cache_options"] = {"ttl": "30m"}
|
||||
else:
|
||||
model_args["prompt_cache_retention"] = "24h"
|
||||
|
||||
tools: list[ToolParam] = []
|
||||
if chat_log.llm_api:
|
||||
|
||||
@@ -298,13 +298,46 @@
|
||||
])
|
||||
# ---
|
||||
# name: test_model_args[subentry_options0]
|
||||
dict({
|
||||
'max_output_tokens': 3000,
|
||||
'model': 'gpt-4o-mini',
|
||||
'service_tier': 'auto',
|
||||
'store': False,
|
||||
'stream': True,
|
||||
'temperature': 1.0,
|
||||
'top_p': 1.0,
|
||||
})
|
||||
# ---
|
||||
# name: test_model_args[subentry_options1]
|
||||
dict({
|
||||
'include': list([
|
||||
'reasoning.encrypted_content',
|
||||
]),
|
||||
'max_output_tokens': 3000,
|
||||
'model': 'gpt-5.5',
|
||||
'prompt_cache_retention': '24h',
|
||||
'reasoning': dict({
|
||||
'effort': 'low',
|
||||
'summary': 'auto',
|
||||
}),
|
||||
'service_tier': 'auto',
|
||||
'store': False,
|
||||
'stream': True,
|
||||
'text': dict({
|
||||
'verbosity': 'medium',
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_model_args[subentry_options2]
|
||||
dict({
|
||||
'include': list([
|
||||
'reasoning.encrypted_content',
|
||||
]),
|
||||
'max_output_tokens': 3000,
|
||||
'model': 'gpt-5.6-sol',
|
||||
'prompt_cache_retention': '24h',
|
||||
'prompt_cache_options': dict({
|
||||
'ttl': '30m',
|
||||
}),
|
||||
'reasoning': dict({
|
||||
'effort': 'low',
|
||||
'mode': 'pro',
|
||||
@@ -318,6 +351,96 @@
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_model_args[subentry_options3]
|
||||
dict({
|
||||
'include': list([
|
||||
'reasoning.encrypted_content',
|
||||
]),
|
||||
'max_output_tokens': 3000,
|
||||
'model': 'gpt-5.6-sol',
|
||||
'prompt_cache_options': dict({
|
||||
'ttl': '30m',
|
||||
}),
|
||||
'reasoning': dict({
|
||||
'effort': 'none',
|
||||
'summary': 'auto',
|
||||
}),
|
||||
'service_tier': 'auto',
|
||||
'store': False,
|
||||
'stream': True,
|
||||
'temperature': 0.5,
|
||||
'text': dict({
|
||||
'verbosity': 'medium',
|
||||
}),
|
||||
'top_p': 0.9,
|
||||
})
|
||||
# ---
|
||||
# name: test_model_args[subentry_options4]
|
||||
dict({
|
||||
'include': list([
|
||||
'reasoning.encrypted_content',
|
||||
]),
|
||||
'max_output_tokens': 3000,
|
||||
'model': 'gpt-6-astra',
|
||||
'prompt_cache_options': dict({
|
||||
'ttl': '30m',
|
||||
}),
|
||||
'reasoning': dict({
|
||||
'effort': 'low',
|
||||
'summary': 'auto',
|
||||
}),
|
||||
'service_tier': 'auto',
|
||||
'store': False,
|
||||
'stream': True,
|
||||
'text': dict({
|
||||
'verbosity': 'medium',
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_model_args[subentry_options5]
|
||||
dict({
|
||||
'include': list([
|
||||
'reasoning.encrypted_content',
|
||||
]),
|
||||
'max_output_tokens': 3000,
|
||||
'model': 'gpt-6-astra',
|
||||
'prompt_cache_options': dict({
|
||||
'ttl': '30m',
|
||||
}),
|
||||
'reasoning': dict({
|
||||
'effort': 'max',
|
||||
'mode': 'pro',
|
||||
'summary': 'detailed',
|
||||
}),
|
||||
'service_tier': 'auto',
|
||||
'store': False,
|
||||
'stream': True,
|
||||
'text': dict({
|
||||
'verbosity': 'low',
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_model_args[subentry_options6]
|
||||
dict({
|
||||
'include': list([
|
||||
'reasoning.encrypted_content',
|
||||
]),
|
||||
'max_output_tokens': 3000,
|
||||
'model': 'gpt-6-astra',
|
||||
'prompt_cache_options': dict({
|
||||
'ttl': '30m',
|
||||
}),
|
||||
'reasoning': dict({
|
||||
'effort': 'high',
|
||||
}),
|
||||
'service_tier': 'auto',
|
||||
'store': False,
|
||||
'stream': True,
|
||||
'text': dict({
|
||||
'verbosity': 'high',
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_web_search[False]
|
||||
list([
|
||||
dict({
|
||||
|
||||
@@ -275,6 +275,7 @@ async def test_subentry_unsupported_model(
|
||||
("gpt-5.5", ["none", "low", "medium", "high", "xhigh"]),
|
||||
("gpt-5.5-pro", ["medium", "high", "xhigh"]),
|
||||
("gpt-5.6", ["none", "low", "medium", "high", "xhigh", "max"]),
|
||||
("gpt-6-astra", ["low", "medium", "high", "xhigh", "max"]),
|
||||
],
|
||||
)
|
||||
async def test_subentry_reasoning_effort_list(
|
||||
@@ -327,6 +328,7 @@ async def test_subentry_reasoning_effort_list(
|
||||
("gpt-5", True),
|
||||
("gpt-5-mini", True),
|
||||
("gpt-5-pro", True),
|
||||
("gpt-6-astra", True),
|
||||
("gpt-4o", False),
|
||||
("gpt-4.1", False),
|
||||
],
|
||||
@@ -379,6 +381,7 @@ async def test_subentry_reasoning_summary_visibility(
|
||||
("o4-mini", ["off", "auto", "detailed"]),
|
||||
("gpt-5", ["off", "auto", "concise", "detailed"]),
|
||||
("gpt-5-mini", ["off", "auto", "concise", "detailed"]),
|
||||
("gpt-6-astra", ["off", "auto", "concise", "detailed"]),
|
||||
],
|
||||
)
|
||||
async def test_subentry_reasoning_summary_options(
|
||||
@@ -1090,15 +1093,46 @@ async def test_form_invalid_auth(hass: HomeAssistant, side_effect, error) -> Non
|
||||
CONF_WEB_SEARCH_INLINE_CITATIONS: True,
|
||||
},
|
||||
),
|
||||
(
|
||||
{},
|
||||
(
|
||||
{CONF_RECOMMENDED: False},
|
||||
{CONF_CHAT_MODEL: "gpt-6-astra"},
|
||||
{
|
||||
CONF_REASONING_EFFORT: "max",
|
||||
CONF_REASONING_SUMMARY: "detailed",
|
||||
CONF_PRO_MODE: True,
|
||||
CONF_VERBOSITY: "low",
|
||||
},
|
||||
),
|
||||
{
|
||||
CONF_RECOMMENDED: False,
|
||||
CONF_CHAT_MODEL: "gpt-6-astra",
|
||||
CONF_MAX_TOKENS: RECOMMENDED_MAX_TOKENS,
|
||||
CONF_TOP_P: RECOMMENDED_TOP_P,
|
||||
CONF_TEMPERATURE: 1.0,
|
||||
CONF_STORE_RESPONSES: False,
|
||||
CONF_CODE_INTERPRETER: False,
|
||||
CONF_REASONING_EFFORT: "max",
|
||||
CONF_REASONING_SUMMARY: "detailed",
|
||||
CONF_PRO_MODE: True,
|
||||
CONF_VERBOSITY: "low",
|
||||
CONF_SERVICE_TIER: "auto",
|
||||
CONF_WEB_SEARCH: False,
|
||||
CONF_WEB_SEARCH_CONTEXT_SIZE: "medium",
|
||||
CONF_WEB_SEARCH_USER_LOCATION: False,
|
||||
CONF_WEB_SEARCH_INLINE_CITATIONS: False,
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("mock_init_component")
|
||||
async def test_subentry_switching(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry,
|
||||
mock_init_component,
|
||||
current_options,
|
||||
new_options,
|
||||
expected_options,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
current_options: dict[str, str | float | bool | list[str]],
|
||||
new_options: tuple[dict[str, str | float | bool | list[str]], ...],
|
||||
expected_options: dict[str, str | float | bool | list[str]],
|
||||
) -> None:
|
||||
"""Test the subentry form."""
|
||||
subentry = next(
|
||||
|
||||
@@ -22,9 +22,13 @@ from homeassistant.components.openai_conversation.const import (
|
||||
CONF_CHAT_MODEL,
|
||||
CONF_CODE_INTERPRETER,
|
||||
CONF_PRO_MODE,
|
||||
CONF_REASONING_EFFORT,
|
||||
CONF_REASONING_SUMMARY,
|
||||
CONF_SERVICE_TIER,
|
||||
CONF_STORE_RESPONSES,
|
||||
CONF_TEMPERATURE,
|
||||
CONF_TOP_P,
|
||||
CONF_VERBOSITY,
|
||||
CONF_WEB_SEARCH,
|
||||
CONF_WEB_SEARCH_CITY,
|
||||
CONF_WEB_SEARCH_CONTEXT_SIZE,
|
||||
@@ -821,7 +825,34 @@ async def test_flex_tier_retry(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"subentry_options", [{CONF_CHAT_MODEL: "gpt-5.6-sol", CONF_PRO_MODE: True}]
|
||||
"subentry_options",
|
||||
[
|
||||
{CONF_CHAT_MODEL: "gpt-4o-mini"},
|
||||
{CONF_CHAT_MODEL: "gpt-5.5"},
|
||||
{CONF_CHAT_MODEL: "gpt-5.6-sol", CONF_PRO_MODE: True},
|
||||
{
|
||||
CONF_CHAT_MODEL: "gpt-5.6-sol",
|
||||
CONF_REASONING_EFFORT: "none",
|
||||
CONF_TEMPERATURE: 0.5,
|
||||
CONF_TOP_P: 0.9,
|
||||
},
|
||||
{CONF_CHAT_MODEL: "gpt-6-astra"},
|
||||
{
|
||||
CONF_CHAT_MODEL: "gpt-6-astra",
|
||||
CONF_REASONING_EFFORT: "max",
|
||||
CONF_PRO_MODE: True,
|
||||
CONF_REASONING_SUMMARY: "detailed",
|
||||
CONF_VERBOSITY: "low",
|
||||
CONF_TEMPERATURE: 0.5,
|
||||
CONF_TOP_P: 0.9,
|
||||
},
|
||||
{
|
||||
CONF_CHAT_MODEL: "gpt-6-astra",
|
||||
CONF_REASONING_EFFORT: "high",
|
||||
CONF_REASONING_SUMMARY: "off",
|
||||
CONF_VERBOSITY: "high",
|
||||
},
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("mock_init_component")
|
||||
async def test_model_args(
|
||||
@@ -829,7 +860,7 @@ async def test_model_args(
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_create_stream: AsyncMock,
|
||||
snapshot: SnapshotAssertion,
|
||||
subentry_options: dict[str, str | bool],
|
||||
subentry_options: dict[str, str | bool | float],
|
||||
) -> None:
|
||||
"""Test model arguments for various configuration."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user