Add API key reconfiguration to OpenAI Conversation (#182798)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ffd3b066-aaf0-4f57-8d29-aae9e67b6fbb
Copilot-Session: 4a94f170-86fa-48c6-a11d-660ca363cb4f
This commit is contained in:
Brian Exelbierd
2026-09-24 21:12:34 +02:00
committed by GitHub
co-authored by Copilot
parent 8df9e61c68
commit 309e8ee7db
3 changed files with 88 additions and 8 deletions
@@ -11,6 +11,7 @@ import probatio
from homeassistant.components.zone import ENTITY_ID_HOME
from homeassistant.config_entries import (
SOURCE_REAUTH,
SOURCE_RECONFIGURE,
ConfigEntry,
ConfigEntryState,
ConfigFlow,
@@ -134,7 +135,12 @@ class OpenAIConfigFlow(ConfigFlow, domain=DOMAIN):
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle the initial step."""
return await self._async_step_api_key(user_input, "user")
async def _async_step_api_key(
self, user_input: dict[str, Any] | None, step_id: str
) -> ConfigFlowResult:
"""Handle an API key form."""
errors: dict[str, str] = {}
if user_input is not None:
@@ -149,9 +155,18 @@ class OpenAIConfigFlow(ConfigFlow, domain=DOMAIN):
_LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
else:
if self.source == SOURCE_REAUTH:
if self.source in (SOURCE_REAUTH, SOURCE_RECONFIGURE):
entry = (
self._get_reauth_entry()
if self.source == SOURCE_REAUTH
else self._get_reconfigure_entry()
)
if entry.update_listeners:
return self.async_update_and_abort(
entry, data_updates=user_input
)
return self.async_update_reload_and_abort(
self._get_reauth_entry(), data_updates=user_input
entry, data_updates=user_input
)
return self.async_create_entry(
title="ChatGPT",
@@ -185,7 +200,7 @@ class OpenAIConfigFlow(ConfigFlow, domain=DOMAIN):
)
return self.async_show_form(
step_id="user",
step_id=step_id,
data_schema=self.add_suggested_values_to_schema(
STEP_USER_DATA_SCHEMA, user_input
),
@@ -205,12 +220,13 @@ class OpenAIConfigFlow(ConfigFlow, domain=DOMAIN):
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Dialog that informs the user that reauth is required."""
if not user_input:
return self.async_show_form(
step_id="reauth_confirm", data_schema=STEP_USER_DATA_SCHEMA
)
return await self._async_step_api_key(user_input, "reauth_confirm")
return await self.async_step_user(user_input)
async def async_step_reconfigure(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle reconfiguration of the API key."""
return await self._async_step_api_key(user_input, "reconfigure")
@classmethod
@callback
@@ -18,6 +18,15 @@
},
"description": "Reauthentication required. Please enter your updated API key."
},
"reconfigure": {
"data": {
"api_key": "[%key:common::config_flow::data::api_key%]"
},
"data_description": {
"api_key": "[%key:component::openai_conversation::config::step::user::data_description::api_key%]"
},
"description": "Enter your updated OpenAI API key."
},
"user": {
"data": {
"api_key": "[%key:common::config_flow::data::api_key%]"
@@ -1646,6 +1646,61 @@ async def test_reauth(hass: HomeAssistant) -> None:
assert mock_config_entry.data[CONF_API_KEY] == "new_api_key"
@pytest.mark.usefixtures("mock_init_component")
async def test_reconfigure(
hass: HomeAssistant, mock_config_entry: MockConfigEntry
) -> None:
"""Test the API key can be reconfigured."""
result = await mock_config_entry.start_reconfigure_flow(hass)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "reconfigure"
with (
patch(
"homeassistant.components.openai_conversation.config_flow.openai.resources.models.AsyncModels.list",
new_callable=AsyncMock,
),
patch(
"homeassistant.config_entries.ConfigEntries.async_reload"
) as mock_async_reload,
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {CONF_API_KEY: "new_api_key"}
)
await hass.async_block_till_done()
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "reconfigure_successful"
assert mock_config_entry.data[CONF_API_KEY] == "new_api_key"
assert mock_async_reload.call_count == 1
async def test_reconfigure_invalid_auth(
hass: HomeAssistant, mock_config_entry: MockConfigEntry
) -> None:
"""Test an invalid API key is rejected during reconfiguration."""
result = await mock_config_entry.start_reconfigure_flow(hass)
with patch(
"homeassistant.components.openai_conversation.config_flow.openai.resources.models.AsyncModels.list",
new_callable=AsyncMock,
side_effect=AuthenticationError(
response=httpx.Response(status_code=None, request=""),
body=None,
message=None,
),
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {CONF_API_KEY: "invalid_api_key"}
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "reconfigure"
assert result["errors"] == {"base": "invalid_auth"}
assert mock_config_entry.data[CONF_API_KEY] == "bla"
@pytest.mark.parametrize(
("current_llm_apis", "suggested_llm_apis", "expected_options"),
[