diff --git a/homeassistant/components/conversation/chat_log.py b/homeassistant/components/conversation/chat_log.py index c78f41f3c5c817..7580b878d04efa 100644 --- a/homeassistant/components/conversation/chat_log.py +++ b/homeassistant/components/conversation/chat_log.py @@ -395,7 +395,6 @@ async def async_update_llm_data( llm_context = llm.LLMContext( platform=conversing_domain, context=user_input.context, - user_prompt=user_input.text, language=user_input.language, assistant=DOMAIN, device_id=user_input.device_id, diff --git a/homeassistant/components/google_photos/services.py b/homeassistant/components/google_photos/services.py index a74fabb3b77585..c30259416e5a6b 100644 --- a/homeassistant/components/google_photos/services.py +++ b/homeassistant/components/google_photos/services.py @@ -78,86 +78,85 @@ def _read_file_contents( return results -@callback -def async_setup_services(hass: HomeAssistant) -> None: - """Register Google Photos services.""" - - async def async_handle_upload(call: ServiceCall) -> ServiceResponse: - """Generate content from text and optionally images.""" - config_entry: GooglePhotosConfigEntry | None = ( - hass.config_entries.async_get_entry(call.data[CONF_CONFIG_ENTRY_ID]) +async def _async_handle_upload(call: ServiceCall) -> ServiceResponse: + """Generate content from text and optionally images.""" + config_entry: GooglePhotosConfigEntry | None = ( + call.hass.config_entries.async_get_entry(call.data[CONF_CONFIG_ENTRY_ID]) + ) + if not config_entry: + raise ServiceValidationError( + translation_domain=DOMAIN, + translation_key="integration_not_found", + translation_placeholders={"target": DOMAIN}, ) - if not config_entry: - raise ServiceValidationError( - translation_domain=DOMAIN, - translation_key="integration_not_found", - translation_placeholders={"target": DOMAIN}, - ) - scopes = config_entry.data["token"]["scope"].split(" ") - if UPLOAD_SCOPE not in scopes: - raise HomeAssistantError( - translation_domain=DOMAIN, - translation_key="missing_upload_permission", - translation_placeholders={"target": DOMAIN}, - ) - coordinator = config_entry.runtime_data - client_api = coordinator.client - upload_tasks = [] - file_results = await hass.async_add_executor_job( - _read_file_contents, hass, call.data[CONF_FILENAME] + scopes = config_entry.data["token"]["scope"].split(" ") + if UPLOAD_SCOPE not in scopes: + raise HomeAssistantError( + translation_domain=DOMAIN, + translation_key="missing_upload_permission", + translation_placeholders={"target": DOMAIN}, ) + coordinator = config_entry.runtime_data + client_api = coordinator.client + upload_tasks = [] + file_results = await call.hass.async_add_executor_job( + _read_file_contents, call.hass, call.data[CONF_FILENAME] + ) - album = call.data[CONF_ALBUM] - try: - album_id = await coordinator.get_or_create_album(album) - except GooglePhotosApiError as err: - raise HomeAssistantError( - translation_domain=DOMAIN, - translation_key="create_album_error", - translation_placeholders={"message": str(err)}, - ) from err - - for mime_type, content in file_results: - upload_tasks.append(client_api.upload_content(content, mime_type)) - try: - upload_results = await asyncio.gather(*upload_tasks) - except GooglePhotosApiError as err: - raise HomeAssistantError( - translation_domain=DOMAIN, - translation_key="upload_error", - translation_placeholders={"message": str(err)}, - ) from err - try: - upload_result = await client_api.create_media_items( - [ - NewMediaItem( - SimpleMediaItem(upload_token=upload_result.upload_token) - ) - for upload_result in upload_results - ], - album_id=album_id, - ) - except GooglePhotosApiError as err: - raise HomeAssistantError( - translation_domain=DOMAIN, - translation_key="api_error", - translation_placeholders={"message": str(err)}, - ) from err - if call.return_response: - return { - "media_items": [ - {"media_item_id": item_result.media_item.id} - for item_result in upload_result.new_media_item_results - if item_result.media_item and item_result.media_item.id - ], - "album_id": album_id, - } - return None + album = call.data[CONF_ALBUM] + try: + album_id = await coordinator.get_or_create_album(album) + except GooglePhotosApiError as err: + raise HomeAssistantError( + translation_domain=DOMAIN, + translation_key="create_album_error", + translation_placeholders={"message": str(err)}, + ) from err + + for mime_type, content in file_results: + upload_tasks.append(client_api.upload_content(content, mime_type)) + try: + upload_results = await asyncio.gather(*upload_tasks) + except GooglePhotosApiError as err: + raise HomeAssistantError( + translation_domain=DOMAIN, + translation_key="upload_error", + translation_placeholders={"message": str(err)}, + ) from err + try: + upload_result = await client_api.create_media_items( + [ + NewMediaItem(SimpleMediaItem(upload_token=upload_result.upload_token)) + for upload_result in upload_results + ], + album_id=album_id, + ) + except GooglePhotosApiError as err: + raise HomeAssistantError( + translation_domain=DOMAIN, + translation_key="api_error", + translation_placeholders={"message": str(err)}, + ) from err + if call.return_response: + return { + "media_items": [ + {"media_item_id": item_result.media_item.id} + for item_result in upload_result.new_media_item_results + if item_result.media_item and item_result.media_item.id + ], + "album_id": album_id, + } + return None + + +@callback +def async_setup_services(hass: HomeAssistant) -> None: + """Register Google Photos services.""" hass.services.async_register( DOMAIN, UPLOAD_SERVICE, - async_handle_upload, + _async_handle_upload, schema=UPLOAD_SERVICE_SCHEMA, supports_response=SupportsResponse.OPTIONAL, ) diff --git a/homeassistant/components/mcp_server/http.py b/homeassistant/components/mcp_server/http.py index bc8fdbd56c8214..07284b29434c9f 100644 --- a/homeassistant/components/mcp_server/http.py +++ b/homeassistant/components/mcp_server/http.py @@ -88,7 +88,6 @@ async def get(self, request: web.Request) -> web.StreamResponse: context = llm.LLMContext( platform=DOMAIN, context=self.context(request), - user_prompt=None, language="*", assistant=conversation.DOMAIN, device_id=None, diff --git a/homeassistant/components/nextbus/manifest.json b/homeassistant/components/nextbus/manifest.json index 4b7057f71428ab..c1da33f2555661 100644 --- a/homeassistant/components/nextbus/manifest.json +++ b/homeassistant/components/nextbus/manifest.json @@ -6,5 +6,5 @@ "documentation": "https://www.home-assistant.io/integrations/nextbus", "iot_class": "cloud_polling", "loggers": ["py_nextbus"], - "requirements": ["py-nextbusnext==2.2.0"] + "requirements": ["py-nextbusnext==2.3.0"] } diff --git a/homeassistant/components/reolink/icons.json b/homeassistant/components/reolink/icons.json index c79d9b895fa7e6..d998cc79ce8a3f 100644 --- a/homeassistant/components/reolink/icons.json +++ b/homeassistant/components/reolink/icons.json @@ -220,6 +220,9 @@ "ai_animal_sensitivity": { "default": "mdi:paw" }, + "cry_sensitivity": { + "default": "mdi:emoticon-cry-outline" + }, "crossline_sensitivity": { "default": "mdi:fence" }, diff --git a/homeassistant/components/reolink/number.py b/homeassistant/components/reolink/number.py index e28b8c976975f0..6de702a03953d4 100644 --- a/homeassistant/components/reolink/number.py +++ b/homeassistant/components/reolink/number.py @@ -272,6 +272,18 @@ class ReolinkChimeNumberEntityDescription( value=lambda api, ch: api.ai_sensitivity(ch, "dog_cat"), method=lambda api, ch, value: api.set_ai_sensitivity(ch, int(value), "dog_cat"), ), + ReolinkNumberEntityDescription( + key="cry_sensitivity", + cmd_key="299", + translation_key="cry_sensitivity", + entity_category=EntityCategory.CONFIG, + native_step=1, + native_min_value=1, + native_max_value=5, + supported=lambda api, ch: api.supported(ch, "ai_cry"), + value=lambda api, ch: api.baichuan.cry_sensitivity(ch), + method=lambda api, ch, value: api.baichuan.set_cry_detection(ch, int(value)), + ), ReolinkNumberEntityDescription( key="ai_face_delay", cmd_key="GetAiAlarm", diff --git a/homeassistant/components/reolink/strings.json b/homeassistant/components/reolink/strings.json index 45448e2a03ca95..59d2ce95df483f 100644 --- a/homeassistant/components/reolink/strings.json +++ b/homeassistant/components/reolink/strings.json @@ -571,6 +571,9 @@ "ai_animal_sensitivity": { "name": "AI animal sensitivity" }, + "cry_sensitivity": { + "name": "Baby cry sensitivity" + }, "crossline_sensitivity": { "name": "AI crossline {zone_name} sensitivity" }, diff --git a/homeassistant/helpers/llm.py b/homeassistant/helpers/llm.py index adf113e0f3036d..51b5510495f50f 100644 --- a/homeassistant/helpers/llm.py +++ b/homeassistant/helpers/llm.py @@ -160,11 +160,19 @@ class LLMContext: """Tool input to be processed.""" platform: str + """Integration that is handling the LLM request.""" + context: Context | None - user_prompt: str | None + """Context of the LLM request.""" + language: str | None + """Language of the LLM request.""" + assistant: str | None + """Assistant domain that is handling the LLM request.""" + device_id: str | None + """Device that is making the request.""" @dataclass(slots=True) @@ -302,7 +310,7 @@ async def async_call( platform=llm_context.platform, intent_type=self.name, slots=slots, - text_input=llm_context.user_prompt, + text_input=None, context=llm_context.context, language=llm_context.language, assistant=llm_context.assistant, diff --git a/homeassistant/scripts/__init__.py b/homeassistant/scripts/__init__.py index f0600b70f48e1b..52d96109bf2b6b 100644 --- a/homeassistant/scripts/__init__.py +++ b/homeassistant/scripts/__init__.py @@ -46,10 +46,8 @@ def run(args: list[str]) -> int: config_dir = extract_config_dir() - loop = asyncio.get_event_loop() - if not is_virtual_env(): - loop.run_until_complete(async_mount_local_lib_path(config_dir)) + asyncio.run(async_mount_local_lib_path(config_dir)) _pip_kwargs = pip_kwargs(config_dir) diff --git a/requirements_all.txt b/requirements_all.txt index 7ec909b653fbc6..4d75049746bda6 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1762,7 +1762,7 @@ py-madvr2==1.6.32 py-melissa-climate==2.1.4 # homeassistant.components.nextbus -py-nextbusnext==2.2.0 +py-nextbusnext==2.3.0 # homeassistant.components.nightscout py-nightscout==1.2.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index dd69b70b90d509..2b95d114d76176 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1485,7 +1485,7 @@ py-madvr2==1.6.32 py-melissa-climate==2.1.4 # homeassistant.components.nextbus -py-nextbusnext==2.2.0 +py-nextbusnext==2.3.0 # homeassistant.components.nightscout py-nightscout==1.2.2 diff --git a/tests/components/anthropic/test_conversation.py b/tests/components/anthropic/test_conversation.py index 3e01e91976d213..6aadcf3eeb4d33 100644 --- a/tests/components/anthropic/test_conversation.py +++ b/tests/components/anthropic/test_conversation.py @@ -415,7 +415,6 @@ def completion_result(*args, messages, **kwargs): llm.LLMContext( platform="anthropic", context=context, - user_prompt="Please call the test function", language="en", assistant="conversation", device_id=None, @@ -510,7 +509,6 @@ def completion_result(*args, messages, **kwargs): llm.LLMContext( platform="anthropic", context=context, - user_prompt="Please call the test function", language="en", assistant="conversation", device_id=None, diff --git a/tests/components/mcp/test_init.py b/tests/components/mcp/test_init.py index 045fb99e181f9a..00666e71d051fb 100644 --- a/tests/components/mcp/test_init.py +++ b/tests/components/mcp/test_init.py @@ -58,7 +58,6 @@ def create_llm_context() -> llm.LLMContext: return llm.LLMContext( platform="test_platform", context=Context(), - user_prompt="test_text", language="*", assistant="conversation", device_id=None, diff --git a/tests/components/ollama/test_conversation.py b/tests/components/ollama/test_conversation.py index 8e54018a14d496..e83c2a3495f8e7 100644 --- a/tests/components/ollama/test_conversation.py +++ b/tests/components/ollama/test_conversation.py @@ -284,7 +284,6 @@ def completion_result(*args, messages, **kwargs): llm.LLMContext( platform="ollama", context=context, - user_prompt="Please call the test function", language="en", assistant="conversation", device_id=None, @@ -369,7 +368,6 @@ def completion_result(*args, messages, **kwargs): llm.LLMContext( platform="ollama", context=context, - user_prompt="Please call the test function", language="en", assistant="conversation", device_id=None, diff --git a/tests/components/reolink/snapshots/test_diagnostics.ambr b/tests/components/reolink/snapshots/test_diagnostics.ambr index 771aeba2a9e564..d81b39738e509b 100644 --- a/tests/components/reolink/snapshots/test_diagnostics.ambr +++ b/tests/components/reolink/snapshots/test_diagnostics.ambr @@ -72,6 +72,10 @@ '0': 1, 'null': 1, }), + '299': dict({ + '0': 1, + 'null': 1, + }), 'DingDongOpt': dict({ '0': 2, 'null': 2, diff --git a/tests/helpers/test_llm.py b/tests/helpers/test_llm.py index 1a9225c505bb5e..98dee920bd9674 100644 --- a/tests/helpers/test_llm.py +++ b/tests/helpers/test_llm.py @@ -36,7 +36,6 @@ def llm_context() -> llm.LLMContext: return llm.LLMContext( platform="", context=None, - user_prompt=None, language=None, assistant=None, device_id=None, @@ -162,7 +161,6 @@ async def test_assist_api( llm_context = llm.LLMContext( platform="test_platform", context=test_context, - user_prompt="test_text", language="*", assistant="conversation", device_id=None, @@ -237,7 +235,7 @@ class MyIntentHandler(intent.IntentHandler): "area": {"value": "kitchen"}, "floor": {"value": "ground_floor"}, }, - text_input="test_text", + text_input=None, context=test_context, language="*", assistant="conversation", @@ -296,7 +294,7 @@ class MyIntentHandler(intent.IntentHandler): "preferred_area_id": {"value": area.id}, "preferred_floor_id": {"value": floor.floor_id}, }, - text_input="test_text", + text_input=None, context=test_context, language="*", assistant="conversation", @@ -412,7 +410,6 @@ async def test_assist_api_prompt( llm_context = llm.LLMContext( platform="test_platform", context=context, - user_prompt="test_text", language="*", assistant="conversation", device_id=None, @@ -760,7 +757,6 @@ async def test_script_tool( llm_context = llm.LLMContext( platform="test_platform", context=context, - user_prompt="test_text", language="*", assistant="conversation", device_id=None, @@ -961,7 +957,6 @@ async def test_script_tool_name(hass: HomeAssistant) -> None: llm_context = llm.LLMContext( platform="test_platform", context=context, - user_prompt="test_text", language="*", assistant="conversation", device_id=None, @@ -1241,7 +1236,6 @@ async def test_calendar_get_events_tool(hass: HomeAssistant) -> None: llm_context = llm.LLMContext( platform="test_platform", context=context, - user_prompt="test_text", language="*", assistant="conversation", device_id=None, @@ -1344,7 +1338,6 @@ async def test_todo_get_items_tool(hass: HomeAssistant) -> None: llm_context = llm.LLMContext( platform="test_platform", context=context, - user_prompt="test_text", language="*", assistant="conversation", device_id=None, @@ -1451,7 +1444,6 @@ async def test_no_tools_exposed(hass: HomeAssistant) -> None: llm_context = llm.LLMContext( platform="test_platform", context=context, - user_prompt="test_text", language="*", assistant="conversation", device_id=None, diff --git a/tests/scripts/test_check_config.py b/tests/scripts/test_check_config.py index 3a2007060ae81c..2bb58cd4d6842c 100644 --- a/tests/scripts/test_check_config.py +++ b/tests/scripts/test_check_config.py @@ -43,7 +43,7 @@ def mock_is_file(): """Mock is_file.""" # All files exist except for the old entity registry file with patch( - "os.path.isfile", lambda path: not path.endswith("entity_registry.yaml") + "os.path.isfile", lambda path: not str(path).endswith("entity_registry.yaml") ): yield