mirror of
https://github.com/home-assistant/core.git
synced 2026-07-10 16:19:29 +01:00
Add support for storing OpenAI conversation responses (#165723)
This commit is contained in:
@@ -46,6 +46,7 @@ from .const import (
|
||||
CONF_MAX_TOKENS,
|
||||
CONF_PROMPT,
|
||||
CONF_REASONING_EFFORT,
|
||||
CONF_STORE_RESPONSES,
|
||||
CONF_TEMPERATURE,
|
||||
CONF_TOP_P,
|
||||
DEFAULT_AI_TASK_NAME,
|
||||
@@ -58,6 +59,7 @@ from .const import (
|
||||
RECOMMENDED_CHAT_MODEL,
|
||||
RECOMMENDED_MAX_TOKENS,
|
||||
RECOMMENDED_REASONING_EFFORT,
|
||||
RECOMMENDED_STORE_RESPONSES,
|
||||
RECOMMENDED_STT_OPTIONS,
|
||||
RECOMMENDED_TEMPERATURE,
|
||||
RECOMMENDED_TOP_P,
|
||||
@@ -208,7 +210,9 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
CONF_TEMPERATURE, RECOMMENDED_TEMPERATURE
|
||||
),
|
||||
"user": call.context.user_id,
|
||||
"store": False,
|
||||
"store": conversation_subentry.data.get(
|
||||
CONF_STORE_RESPONSES, RECOMMENDED_STORE_RESPONSES
|
||||
),
|
||||
}
|
||||
|
||||
if model.startswith("o"):
|
||||
|
||||
@@ -55,6 +55,7 @@ from .const import (
|
||||
CONF_REASONING_SUMMARY,
|
||||
CONF_RECOMMENDED,
|
||||
CONF_SERVICE_TIER,
|
||||
CONF_STORE_RESPONSES,
|
||||
CONF_TEMPERATURE,
|
||||
CONF_TOP_P,
|
||||
CONF_TTS_SPEED,
|
||||
@@ -82,6 +83,7 @@ from .const import (
|
||||
RECOMMENDED_REASONING_EFFORT,
|
||||
RECOMMENDED_REASONING_SUMMARY,
|
||||
RECOMMENDED_SERVICE_TIER,
|
||||
RECOMMENDED_STORE_RESPONSES,
|
||||
RECOMMENDED_STT_MODEL,
|
||||
RECOMMENDED_STT_OPTIONS,
|
||||
RECOMMENDED_TEMPERATURE,
|
||||
@@ -357,6 +359,10 @@ class OpenAISubentryFlowHandler(ConfigSubentryFlow):
|
||||
CONF_TEMPERATURE,
|
||||
default=RECOMMENDED_TEMPERATURE,
|
||||
): NumberSelector(NumberSelectorConfig(min=0, max=2, step=0.05)),
|
||||
vol.Optional(
|
||||
CONF_STORE_RESPONSES,
|
||||
default=RECOMMENDED_STORE_RESPONSES,
|
||||
): bool,
|
||||
}
|
||||
|
||||
if user_input is not None:
|
||||
@@ -641,7 +647,9 @@ class OpenAISubentryFlowHandler(ConfigSubentryFlow):
|
||||
"strict": False,
|
||||
}
|
||||
},
|
||||
store=False,
|
||||
store=self.options.get(
|
||||
CONF_STORE_RESPONSES, RECOMMENDED_STORE_RESPONSES
|
||||
),
|
||||
)
|
||||
location_data = location_schema(json.loads(response.output_text) or {})
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ CONF_PROMPT = "prompt"
|
||||
CONF_REASONING_EFFORT = "reasoning_effort"
|
||||
CONF_REASONING_SUMMARY = "reasoning_summary"
|
||||
CONF_RECOMMENDED = "recommended"
|
||||
CONF_STORE_RESPONSES = "store_responses"
|
||||
CONF_SERVICE_TIER = "service_tier"
|
||||
CONF_TEMPERATURE = "temperature"
|
||||
CONF_TOP_P = "top_p"
|
||||
@@ -42,6 +43,7 @@ RECOMMENDED_CHAT_MODEL = "gpt-4o-mini"
|
||||
RECOMMENDED_IMAGE_MODEL = "gpt-image-1.5"
|
||||
RECOMMENDED_MAX_TOKENS = 3000
|
||||
RECOMMENDED_REASONING_EFFORT = "low"
|
||||
RECOMMENDED_STORE_RESPONSES = False
|
||||
RECOMMENDED_REASONING_SUMMARY = "auto"
|
||||
RECOMMENDED_SERVICE_TIER = "auto"
|
||||
RECOMMENDED_STT_MODEL = "gpt-4o-mini-transcribe"
|
||||
|
||||
@@ -75,6 +75,7 @@ from .const import (
|
||||
CONF_REASONING_EFFORT,
|
||||
CONF_REASONING_SUMMARY,
|
||||
CONF_SERVICE_TIER,
|
||||
CONF_STORE_RESPONSES,
|
||||
CONF_TEMPERATURE,
|
||||
CONF_TOP_P,
|
||||
CONF_VERBOSITY,
|
||||
@@ -94,6 +95,7 @@ from .const import (
|
||||
RECOMMENDED_REASONING_EFFORT,
|
||||
RECOMMENDED_REASONING_SUMMARY,
|
||||
RECOMMENDED_SERVICE_TIER,
|
||||
RECOMMENDED_STORE_RESPONSES,
|
||||
RECOMMENDED_STT_MODEL,
|
||||
RECOMMENDED_TEMPERATURE,
|
||||
RECOMMENDED_TOP_P,
|
||||
@@ -508,7 +510,7 @@ class OpenAIBaseLLMEntity(Entity):
|
||||
max_output_tokens=options.get(CONF_MAX_TOKENS, RECOMMENDED_MAX_TOKENS),
|
||||
user=chat_log.conversation_id,
|
||||
service_tier=options.get(CONF_SERVICE_TIER, RECOMMENDED_SERVICE_TIER),
|
||||
store=False,
|
||||
store=options.get(CONF_STORE_RESPONSES, RECOMMENDED_STORE_RESPONSES),
|
||||
stream=True,
|
||||
)
|
||||
|
||||
@@ -611,8 +613,10 @@ class OpenAIBaseLLMEntity(Entity):
|
||||
if image_model != "gpt-image-1-mini":
|
||||
image_tool["input_fidelity"] = "high"
|
||||
tools.append(image_tool)
|
||||
# Keep image state on OpenAI so follow-up prompts can continue by
|
||||
# conversation ID without resending the generated image data.
|
||||
model_args["store"] = True
|
||||
model_args["tool_choice"] = ToolChoiceTypesParam(type="image_generation")
|
||||
model_args["store"] = True # Avoid sending image data back and forth
|
||||
|
||||
if tools:
|
||||
model_args["tools"] = tools
|
||||
|
||||
@@ -51,9 +51,13 @@
|
||||
"data": {
|
||||
"chat_model": "[%key:common::generic::model%]",
|
||||
"max_tokens": "[%key:component::openai_conversation::config_subentries::conversation::step::advanced::data::max_tokens%]",
|
||||
"store_responses": "[%key:component::openai_conversation::config_subentries::conversation::step::advanced::data::store_responses%]",
|
||||
"temperature": "[%key:component::openai_conversation::config_subentries::conversation::step::advanced::data::temperature%]",
|
||||
"top_p": "[%key:component::openai_conversation::config_subentries::conversation::step::advanced::data::top_p%]"
|
||||
},
|
||||
"data_description": {
|
||||
"store_responses": "[%key:component::openai_conversation::config_subentries::conversation::step::advanced::data_description::store_responses%]"
|
||||
},
|
||||
"title": "[%key:component::openai_conversation::config_subentries::conversation::step::advanced::title%]"
|
||||
},
|
||||
"init": {
|
||||
@@ -109,9 +113,13 @@
|
||||
"data": {
|
||||
"chat_model": "[%key:common::generic::model%]",
|
||||
"max_tokens": "Maximum tokens to return in response",
|
||||
"store_responses": "Store requests and responses in OpenAI",
|
||||
"temperature": "Temperature",
|
||||
"top_p": "Top P"
|
||||
},
|
||||
"data_description": {
|
||||
"store_responses": "If enabled, requests and responses are stored by OpenAI and visible in your OpenAI dashboard logs"
|
||||
},
|
||||
"title": "Advanced settings"
|
||||
},
|
||||
"init": {
|
||||
|
||||
@@ -10,6 +10,7 @@ import voluptuous as vol
|
||||
|
||||
from homeassistant.components import ai_task, media_source
|
||||
from homeassistant.components.openai_conversation import DOMAIN
|
||||
from homeassistant.components.openai_conversation.const import CONF_STORE_RESPONSES
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import entity_registry as er, issue_registry as ir, selector
|
||||
@@ -20,11 +21,13 @@ from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_init_component")
|
||||
@pytest.mark.parametrize("expected_store", [False, True])
|
||||
async def test_generate_data(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_create_stream: AsyncMock,
|
||||
entity_registry: er.EntityRegistry,
|
||||
expected_store: bool,
|
||||
) -> None:
|
||||
"""Test AI Task data generation."""
|
||||
entity_id = "ai_task.openai_ai_task"
|
||||
@@ -38,6 +41,12 @@ async def test_generate_data(
|
||||
if entry.subentry_type == "ai_task_data"
|
||||
)
|
||||
)
|
||||
hass.config_entries.async_update_subentry(
|
||||
mock_config_entry,
|
||||
ai_task_entry,
|
||||
data={**ai_task_entry.data, CONF_STORE_RESPONSES: expected_store},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert entity_entry is not None
|
||||
assert entity_entry.config_entry_id == mock_config_entry.entry_id
|
||||
assert entity_entry.config_subentry_id == ai_task_entry.subentry_id
|
||||
@@ -55,6 +64,8 @@ async def test_generate_data(
|
||||
)
|
||||
|
||||
assert result.data == "The test data"
|
||||
assert mock_create_stream.call_args is not None
|
||||
assert mock_create_stream.call_args.kwargs["store"] is expected_store
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_init_component")
|
||||
@@ -212,6 +223,7 @@ async def test_generate_data_with_attachments(
|
||||
|
||||
@pytest.mark.usefixtures("mock_init_component")
|
||||
@pytest.mark.freeze_time("2025-06-14 22:59:00")
|
||||
@pytest.mark.parametrize("configured_store", [False, True])
|
||||
@pytest.mark.parametrize(
|
||||
"image_model", ["gpt-image-1.5", "gpt-image-1", "gpt-image-1-mini"]
|
||||
)
|
||||
@@ -222,6 +234,7 @@ async def test_generate_image(
|
||||
entity_registry: er.EntityRegistry,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
image_model: str,
|
||||
configured_store: bool,
|
||||
) -> None:
|
||||
"""Test AI Task image generation."""
|
||||
entity_id = "ai_task.openai_ai_task"
|
||||
@@ -238,7 +251,11 @@ async def test_generate_image(
|
||||
hass.config_entries.async_update_subentry(
|
||||
mock_config_entry,
|
||||
ai_task_entry,
|
||||
data={"image_model": image_model},
|
||||
data={
|
||||
**ai_task_entry.data,
|
||||
"image_model": image_model,
|
||||
CONF_STORE_RESPONSES: configured_store,
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert entity_entry is not None
|
||||
@@ -277,6 +294,8 @@ async def test_generate_image(
|
||||
assert result["model"] == image_model
|
||||
|
||||
mock_upload_media.assert_called_once()
|
||||
assert mock_create_stream.call_args is not None
|
||||
assert mock_create_stream.call_args.kwargs["store"] is True
|
||||
image_data = mock_upload_media.call_args[0][1]
|
||||
assert image_data.file.getvalue() == b"A"
|
||||
assert image_data.content_type == "image/png"
|
||||
|
||||
@@ -21,6 +21,7 @@ from homeassistant.components.openai_conversation.const import (
|
||||
CONF_REASONING_SUMMARY,
|
||||
CONF_RECOMMENDED,
|
||||
CONF_SERVICE_TIER,
|
||||
CONF_STORE_RESPONSES,
|
||||
CONF_TEMPERATURE,
|
||||
CONF_TOP_P,
|
||||
CONF_TTS_SPEED,
|
||||
@@ -539,6 +540,7 @@ async def test_form_invalid_auth(hass: HomeAssistant, side_effect, error) -> Non
|
||||
CONF_CHAT_MODEL: "o1-pro",
|
||||
CONF_TOP_P: RECOMMENDED_TOP_P,
|
||||
CONF_MAX_TOKENS: 10000,
|
||||
CONF_STORE_RESPONSES: False,
|
||||
CONF_REASONING_EFFORT: "high",
|
||||
CONF_CODE_INTERPRETER: True,
|
||||
},
|
||||
@@ -575,6 +577,7 @@ async def test_form_invalid_auth(hass: HomeAssistant, side_effect, error) -> Non
|
||||
CONF_CHAT_MODEL: RECOMMENDED_CHAT_MODEL,
|
||||
CONF_TOP_P: RECOMMENDED_TOP_P,
|
||||
CONF_MAX_TOKENS: RECOMMENDED_MAX_TOKENS,
|
||||
CONF_STORE_RESPONSES: False,
|
||||
CONF_SERVICE_TIER: "auto",
|
||||
CONF_WEB_SEARCH: True,
|
||||
CONF_WEB_SEARCH_CONTEXT_SIZE: "low",
|
||||
@@ -592,6 +595,7 @@ async def test_form_invalid_auth(hass: HomeAssistant, side_effect, error) -> Non
|
||||
CONF_CHAT_MODEL: "gpt-4o",
|
||||
CONF_TOP_P: 0.9,
|
||||
CONF_MAX_TOKENS: 1000,
|
||||
CONF_STORE_RESPONSES: True,
|
||||
CONF_WEB_SEARCH: True,
|
||||
CONF_WEB_SEARCH_CONTEXT_SIZE: "low",
|
||||
CONF_WEB_SEARCH_USER_LOCATION: True,
|
||||
@@ -613,6 +617,7 @@ async def test_form_invalid_auth(hass: HomeAssistant, side_effect, error) -> Non
|
||||
CONF_CHAT_MODEL: "gpt-4o",
|
||||
CONF_TOP_P: 0.9,
|
||||
CONF_MAX_TOKENS: 1000,
|
||||
CONF_STORE_RESPONSES: True,
|
||||
},
|
||||
{
|
||||
CONF_WEB_SEARCH: True,
|
||||
@@ -630,6 +635,7 @@ async def test_form_invalid_auth(hass: HomeAssistant, side_effect, error) -> Non
|
||||
CONF_CHAT_MODEL: "gpt-4o",
|
||||
CONF_TOP_P: 0.9,
|
||||
CONF_MAX_TOKENS: 1000,
|
||||
CONF_STORE_RESPONSES: True,
|
||||
CONF_SERVICE_TIER: "default",
|
||||
CONF_WEB_SEARCH: True,
|
||||
CONF_WEB_SEARCH_CONTEXT_SIZE: "low",
|
||||
@@ -686,6 +692,7 @@ async def test_form_invalid_auth(hass: HomeAssistant, side_effect, error) -> Non
|
||||
CONF_CHAT_MODEL: "gpt-5",
|
||||
CONF_TOP_P: 0.9,
|
||||
CONF_MAX_TOKENS: 1000,
|
||||
CONF_STORE_RESPONSES: False,
|
||||
CONF_REASONING_EFFORT: "minimal",
|
||||
CONF_REASONING_SUMMARY: RECOMMENDED_REASONING_SUMMARY,
|
||||
CONF_CODE_INTERPRETER: False,
|
||||
@@ -799,6 +806,7 @@ async def test_form_invalid_auth(hass: HomeAssistant, side_effect, error) -> Non
|
||||
CONF_CHAT_MODEL: "o3-mini",
|
||||
CONF_TOP_P: 0.9,
|
||||
CONF_MAX_TOKENS: 1000,
|
||||
CONF_STORE_RESPONSES: False,
|
||||
CONF_REASONING_EFFORT: "low",
|
||||
CONF_CODE_INTERPRETER: True,
|
||||
},
|
||||
@@ -844,6 +852,7 @@ async def test_form_invalid_auth(hass: HomeAssistant, side_effect, error) -> Non
|
||||
CONF_CHAT_MODEL: "gpt-4o",
|
||||
CONF_TOP_P: 0.9,
|
||||
CONF_MAX_TOKENS: 1000,
|
||||
CONF_STORE_RESPONSES: False,
|
||||
CONF_SERVICE_TIER: "priority",
|
||||
CONF_WEB_SEARCH: True,
|
||||
CONF_WEB_SEARCH_CONTEXT_SIZE: "high",
|
||||
@@ -896,6 +905,7 @@ async def test_form_invalid_auth(hass: HomeAssistant, side_effect, error) -> Non
|
||||
CONF_CHAT_MODEL: "gpt-5-pro",
|
||||
CONF_TOP_P: 0.9,
|
||||
CONF_MAX_TOKENS: 1000,
|
||||
CONF_STORE_RESPONSES: False,
|
||||
CONF_REASONING_SUMMARY: RECOMMENDED_REASONING_SUMMARY,
|
||||
CONF_VERBOSITY: "medium",
|
||||
CONF_WEB_SEARCH: True,
|
||||
@@ -915,7 +925,11 @@ async def test_subentry_switching(
|
||||
expected_options,
|
||||
) -> None:
|
||||
"""Test the subentry form."""
|
||||
subentry = next(iter(mock_config_entry.subentries.values()))
|
||||
subentry = next(
|
||||
sub
|
||||
for sub in mock_config_entry.subentries.values()
|
||||
if sub.subentry_type == "conversation"
|
||||
)
|
||||
hass.config_entries.async_update_subentry(
|
||||
mock_config_entry, subentry, data=current_options
|
||||
)
|
||||
@@ -952,11 +966,19 @@ async def test_subentry_switching(
|
||||
assert subentry.data == expected_options
|
||||
|
||||
|
||||
@pytest.mark.parametrize("store_responses", [False, True])
|
||||
async def test_subentry_web_search_user_location(
|
||||
hass: HomeAssistant, mock_config_entry, mock_init_component
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry,
|
||||
mock_init_component,
|
||||
store_responses: bool,
|
||||
) -> None:
|
||||
"""Test fetching user location."""
|
||||
subentry = next(iter(mock_config_entry.subentries.values()))
|
||||
subentry = next(
|
||||
sub
|
||||
for sub in mock_config_entry.subentries.values()
|
||||
if sub.subentry_type == "conversation"
|
||||
)
|
||||
subentry_flow = await mock_config_entry.start_subentry_reconfigure_flow(
|
||||
hass, subentry.subentry_id
|
||||
)
|
||||
@@ -982,6 +1004,7 @@ async def test_subentry_web_search_user_location(
|
||||
CONF_CHAT_MODEL: RECOMMENDED_CHAT_MODEL,
|
||||
CONF_TOP_P: RECOMMENDED_TOP_P,
|
||||
CONF_MAX_TOKENS: RECOMMENDED_MAX_TOKENS,
|
||||
CONF_STORE_RESPONSES: store_responses,
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
@@ -1036,6 +1059,7 @@ async def test_subentry_web_search_user_location(
|
||||
mock_create.call_args.kwargs["input"][0]["content"] == "Where are the following"
|
||||
" coordinates located: (37.7749, -122.4194)?"
|
||||
)
|
||||
assert mock_create.call_args.kwargs["store"] is store_responses
|
||||
assert subentry_flow["type"] is FlowResultType.ABORT
|
||||
assert subentry_flow["reason"] == "reconfigure_successful"
|
||||
assert subentry.data == {
|
||||
@@ -1046,6 +1070,7 @@ async def test_subentry_web_search_user_location(
|
||||
CONF_TOP_P: RECOMMENDED_TOP_P,
|
||||
CONF_MAX_TOKENS: RECOMMENDED_MAX_TOKENS,
|
||||
CONF_SERVICE_TIER: "auto",
|
||||
CONF_STORE_RESPONSES: store_responses,
|
||||
CONF_WEB_SEARCH: True,
|
||||
CONF_WEB_SEARCH_CONTEXT_SIZE: "medium",
|
||||
CONF_WEB_SEARCH_USER_LOCATION: True,
|
||||
@@ -1149,6 +1174,7 @@ async def test_creating_ai_task_subentry_advanced(
|
||||
{
|
||||
CONF_CHAT_MODEL: "gpt-4o",
|
||||
CONF_MAX_TOKENS: 200,
|
||||
CONF_STORE_RESPONSES: True,
|
||||
CONF_TEMPERATURE: 0.5,
|
||||
CONF_TOP_P: 0.9,
|
||||
},
|
||||
@@ -1172,6 +1198,7 @@ async def test_creating_ai_task_subentry_advanced(
|
||||
CONF_CHAT_MODEL: "gpt-4o",
|
||||
CONF_IMAGE_MODEL: "gpt-image-1.5",
|
||||
CONF_MAX_TOKENS: 200,
|
||||
CONF_STORE_RESPONSES: True,
|
||||
CONF_TEMPERATURE: 0.5,
|
||||
CONF_TOP_P: 0.9,
|
||||
CONF_CODE_INTERPRETER: False,
|
||||
|
||||
@@ -20,6 +20,7 @@ from homeassistant.components.homeassistant.exposed_entities import async_expose
|
||||
from homeassistant.components.openai_conversation.const import (
|
||||
CONF_CODE_INTERPRETER,
|
||||
CONF_SERVICE_TIER,
|
||||
CONF_STORE_RESPONSES,
|
||||
CONF_WEB_SEARCH,
|
||||
CONF_WEB_SEARCH_CITY,
|
||||
CONF_WEB_SEARCH_CONTEXT_SIZE,
|
||||
@@ -472,6 +473,46 @@ async def test_assist_api_tools_conversion(
|
||||
assert tools
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"expected_store",
|
||||
[
|
||||
False,
|
||||
True,
|
||||
],
|
||||
)
|
||||
async def test_store_responses_forwarded_for_conversation_agent(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_init_component,
|
||||
mock_create_stream: AsyncMock,
|
||||
expected_store: bool,
|
||||
) -> None:
|
||||
"""Test store_responses is forwarded for the conversation agent."""
|
||||
subentry = next(
|
||||
entry
|
||||
for entry in mock_config_entry.subentries.values()
|
||||
if entry.subentry_type == "conversation"
|
||||
)
|
||||
hass.config_entries.async_update_subentry(
|
||||
mock_config_entry,
|
||||
subentry,
|
||||
data={**subentry.data, CONF_STORE_RESPONSES: expected_store},
|
||||
)
|
||||
await hass.config_entries.async_reload(mock_config_entry.entry_id)
|
||||
|
||||
mock_create_stream.return_value = [
|
||||
create_message_item(id="msg_A", text="Hello!", output_index=0)
|
||||
]
|
||||
|
||||
result = await conversation.async_converse(
|
||||
hass, "hello", None, Context(), agent_id=mock_config_entry.entry_id
|
||||
)
|
||||
|
||||
assert result.response.response_type == intent.IntentResponseType.ACTION_DONE
|
||||
assert mock_create_stream.call_args is not None
|
||||
assert mock_create_stream.call_args.kwargs["store"] is expected_store
|
||||
|
||||
|
||||
@pytest.mark.parametrize("inline_citations", [True, False])
|
||||
async def test_web_search(
|
||||
hass: HomeAssistant,
|
||||
|
||||
@@ -19,6 +19,7 @@ from syrupy.filters import props
|
||||
|
||||
from homeassistant.components.openai_conversation import CONF_CHAT_MODEL
|
||||
from homeassistant.components.openai_conversation.const import (
|
||||
CONF_STORE_RESPONSES,
|
||||
DEFAULT_AI_TASK_NAME,
|
||||
DEFAULT_CONVERSATION_NAME,
|
||||
DEFAULT_STT_NAME,
|
||||
@@ -308,6 +309,7 @@ async def test_init_auth_error(
|
||||
assert mock_config_entry.state is ConfigEntryState.SETUP_ERROR
|
||||
|
||||
|
||||
@pytest.mark.parametrize("store_responses", [False, True])
|
||||
@pytest.mark.parametrize(
|
||||
("service_data", "expected_args", "number_of_files"),
|
||||
[
|
||||
@@ -404,18 +406,31 @@ async def test_generate_content_service(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_init_component,
|
||||
store_responses: bool,
|
||||
service_data,
|
||||
expected_args,
|
||||
number_of_files,
|
||||
) -> None:
|
||||
"""Test generate content service."""
|
||||
conversation_subentry = next(
|
||||
sub
|
||||
for sub in mock_config_entry.subentries.values()
|
||||
if sub.subentry_type == "conversation"
|
||||
)
|
||||
hass.config_entries.async_update_subentry(
|
||||
mock_config_entry,
|
||||
conversation_subentry,
|
||||
data={**conversation_subentry.data, CONF_STORE_RESPONSES: store_responses},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
service_data["config_entry"] = mock_config_entry.entry_id
|
||||
expected_args["model"] = "gpt-4o-mini"
|
||||
expected_args["max_output_tokens"] = 3000
|
||||
expected_args["top_p"] = 1.0
|
||||
expected_args["temperature"] = 1.0
|
||||
expected_args["user"] = None
|
||||
expected_args["store"] = False
|
||||
expected_args["store"] = store_responses
|
||||
expected_args["input"][0]["type"] = "message"
|
||||
expected_args["input"][0]["role"] = "user"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user