Expose nevermind intent to LLMs

This commit is contained in:
Paulus Schoutsen 2024-11-30 04:02:43 +00:00
parent e8ced4fa12
commit cf259c2278
3 changed files with 33 additions and 8 deletions

View File

@ -364,7 +364,7 @@ class NevermindIntentHandler(intent.IntentHandler):
"""Takes no action.""" """Takes no action."""
intent_type = intent.INTENT_NEVERMIND intent_type = intent.INTENT_NEVERMIND
description = "Cancels the current request and does nothing" description = "Cancel the current conversation if it was started by mistake or the user wants it to stop."
async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse: async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse:
"""Do nothing and produces an empty response.""" """Do nothing and produces an empty response."""

View File

@ -30,6 +30,7 @@ from homeassistant.exceptions import HomeAssistantError, TemplateError
from homeassistant.helpers import device_registry as dr, intent, llm, template from homeassistant.helpers import device_registry as dr, intent, llm, template
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.util import ulid from homeassistant.util import ulid
from homeassistant.util.json import JsonObjectType
from . import OpenAIConfigEntry from . import OpenAIConfigEntry
from .const import ( from .const import (
@ -292,6 +293,8 @@ class OpenAIConversationEntity(
if not tool_calls or not llm_api: if not tool_calls or not llm_api:
break break
aborting = False
for tool_call in tool_calls: for tool_call in tool_calls:
tool_input = llm.ToolInput( tool_input = llm.ToolInput(
tool_name=tool_call.function.name, tool_name=tool_call.function.name,
@ -301,12 +304,25 @@ class OpenAIConversationEntity(
"Tool call: %s(%s)", tool_input.tool_name, tool_input.tool_args "Tool call: %s(%s)", tool_input.tool_name, tool_input.tool_args
) )
try: # OpenAI requires a tool response for every tool call in history
tool_response = await llm_api.async_call_tool(tool_input) if aborting:
except (HomeAssistantError, vol.Invalid) as e: tool_response: JsonObjectType = {
tool_response = {"error": type(e).__name__} "error": "Aborted",
if str(e): "error_text": "Abort conversation requested",
tool_response["error_text"] = str(e) }
if not aborting:
try:
tool_response = await llm_api.async_call_tool(tool_input)
except llm.AbortConversation as e:
aborting = True
tool_response = {
"error": "Aborted",
"error_text": str(e) or "Abort conversation requested",
}
except (HomeAssistantError, vol.Invalid) as e:
tool_response = {"error": type(e).__name__}
if str(e):
tool_response["error_text"] = str(e)
LOGGER.debug("Tool response: %s", tool_response) LOGGER.debug("Tool response: %s", tool_response)
messages.append( messages.append(
@ -317,6 +333,9 @@ class OpenAIConversationEntity(
) )
) )
if aborting:
break
self.history[conversation_id] = messages self.history[conversation_id] = messages
intent_response = intent.IntentResponse(language=user_input.language) intent_response = intent.IntentResponse(language=user_input.language)

View File

@ -113,6 +113,10 @@ def async_get_apis(hass: HomeAssistant) -> list[API]:
return list(_async_get_apis(hass).values()) return list(_async_get_apis(hass).values())
class AbortConversation(HomeAssistantError):
"""Abort the conversation."""
@dataclass(slots=True) @dataclass(slots=True)
class LLMContext: class LLMContext:
"""Tool input to be processed.""" """Tool input to be processed."""
@ -169,6 +173,9 @@ class APIInstance:
{"tool_name": tool_input.tool_name, "tool_args": tool_input.tool_args}, {"tool_name": tool_input.tool_name, "tool_args": tool_input.tool_args},
) )
if tool_input.tool_name == intent.INTENT_NEVERMIND:
raise AbortConversation("Nevermind intent called")
for tool in self.tools: for tool in self.tools:
if tool.name == tool_input.tool_name: if tool.name == tool_input.tool_name:
break break
@ -273,7 +280,6 @@ class AssistAPI(API):
INTENT_OPEN_COVER, # deprecated INTENT_OPEN_COVER, # deprecated
INTENT_CLOSE_COVER, # deprecated INTENT_CLOSE_COVER, # deprecated
intent.INTENT_GET_STATE, intent.INTENT_GET_STATE,
intent.INTENT_NEVERMIND,
intent.INTENT_TOGGLE, intent.INTENT_TOGGLE,
intent.INTENT_GET_CURRENT_DATE, intent.INTENT_GET_CURRENT_DATE,
intent.INTENT_GET_CURRENT_TIME, intent.INTENT_GET_CURRENT_TIME,