async def test_custom_agent(hass, hass_client): """Test a custom conversation agent.""" class MyAgent(conversation.AbstractConversationAgent): """Test Agent.""" async def async_process(self, text): """Process some text.""" response = intent.IntentResponse() response.async_set_speech("Test response") return response conversation.async_set_agent(hass, MyAgent()) assert await async_setup_component(hass, "conversation", {}) client = await hass_client() resp = await client.post("/api/conversation/process", json={"text": "Test Text"}) assert resp.status == 200 assert await resp.json() == { "card": {}, "speech": { "plain": { "extra_data": None, "speech": "Test response" } }, }
async def async_setup_entry(hass: HomeAssistant, entry: config_entries.ConfigEntry): """Set up Almond config entry.""" websession = aiohttp_client.async_get_clientsession(hass) if entry.data["type"] == TYPE_LOCAL: auth = AlmondLocalAuth(entry.data["host"], websession) else: # OAuth2 implementation = ( await config_entry_oauth2_flow.async_get_config_entry_implementation( hass, entry)) oauth_session = config_entry_oauth2_flow.OAuth2Session( hass, entry, implementation) auth = AlmondOAuth(entry.data["host"], websession, oauth_session) api = WebAlmondAPI(auth) agent = AlmondAgent(hass, api, entry) # Hass.io does its own configuration. if not entry.data.get("is_hassio"): # If we're not starting or local, set up Almond right away if hass.state != CoreState.not_running or entry.data[ "type"] == TYPE_LOCAL: await _configure_almond_for_ha(hass, entry, api) else: # OAuth2 implementations can potentially rely on the HA Cloud url. # This url is not be available until 30 seconds after boot. async def configure_almond(_now): try: await _configure_almond_for_ha(hass, entry, api) except ConfigEntryNotReady: _LOGGER.warning( "Unable to configure Almond to connect to Home Assistant" ) async def almond_hass_start(_event): event.async_call_later(hass, ALMOND_SETUP_DELAY, configure_almond) hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, almond_hass_start) conversation.async_set_agent(hass, agent) return True
async def test_custom_agent(hass, hass_client, hass_admin_user): """Test a custom conversation agent.""" calls = [] class MyAgent(conversation.AbstractConversationAgent): """Test Agent.""" async def async_process(self, text, context, conversation_id): """Process some text.""" calls.append((text, context, conversation_id)) response = intent.IntentResponse() response.async_set_speech("Test response") return response conversation.async_set_agent(hass, MyAgent()) assert await async_setup_component(hass, "conversation", {}) client = await hass_client() resp = await client.post( "/api/conversation/process", json={ "text": "Test Text", "conversation_id": "test-conv-id" }, ) assert resp.status == HTTPStatus.OK assert await resp.json() == { "card": {}, "speech": { "plain": { "extra_data": None, "speech": "Test response" } }, } assert len(calls) == 1 assert calls[0][0] == "Test Text" assert calls[0][1].user_id == hass_admin_user.id assert calls[0][2] == "test-conv-id"
async def async_unload_entry(hass, entry): """Unload Almond.""" conversation.async_set_agent(hass, None) return True
async def async_setup_entry(hass, entry): """Set up Almond config entry.""" websession = aiohttp_client.async_get_clientsession(hass) if entry.data["type"] == TYPE_LOCAL: auth = AlmondLocalAuth(entry.data["host"], websession) else: # OAuth2 implementation = await config_entry_oauth2_flow.async_get_config_entry_implementation( hass, entry) oauth_session = config_entry_oauth2_flow.OAuth2Session( hass, entry, implementation) auth = AlmondOAuth(entry.data["host"], websession, oauth_session) api = WebAlmondAPI(auth) agent = AlmondAgent(hass, api, entry) # Hass.io does its own configuration of Almond. if entry.data.get("is_hassio") or entry.data["type"] != TYPE_LOCAL: conversation.async_set_agent(hass, agent) return True # Configure Almond to connect to Home Assistant store = storage.Store(hass, STORAGE_VERSION, STORAGE_KEY) data = await store.async_load() if data is None: data = {} user = None if "almond_user" in data: user = await hass.auth.async_get_user(data["almond_user"]) if user is None: user = await hass.auth.async_create_system_user( "Almond", [GROUP_ID_ADMIN]) data["almond_user"] = user.id await store.async_save(data) refresh_token = await hass.auth.async_create_refresh_token( user, # Almond will be fine as long as we restart once every 5 years access_token_expiration=timedelta(days=365 * 5), ) # Create long lived access token access_token = hass.auth.async_create_access_token(refresh_token) # Store token in Almond try: with async_timeout.timeout(10): await api.async_create_device({ "kind": "io.home-assistant", "hassUrl": hass.config.api.base_url, "accessToken": access_token, "refreshToken": "", # 5 years from now in ms. "accessTokenExpires": (time.time() + 60 * 60 * 24 * 365 * 5) * 1000, }) except (asyncio.TimeoutError, ClientError) as err: if isinstance(err, asyncio.TimeoutError): msg = "Request timeout" else: msg = err _LOGGER.warning("Unable to configure Almond: %s", msg) await hass.auth.async_remove_refresh_token(refresh_token) raise ConfigEntryNotReady # Clear all other refresh tokens for token in list(user.refresh_tokens.values()): if token.id != refresh_token.id: await hass.auth.async_remove_refresh_token(token) conversation.async_set_agent(hass, agent) return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Unload Almond.""" conversation.async_set_agent(hass, None) return True