Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LLM Tools support for Google Generative AI integration #117644

Merged
merged 28 commits into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
1e4e12d
initial commit
Shulyaka May 16, 2024
37a4faf
Undo prompt chenges
Shulyaka May 17, 2024
d9bd295
Move format_tool out of the class
Shulyaka May 17, 2024
07f1fdc
Merge branch 'dev' into google_ai_tools
Shulyaka May 17, 2024
2e62688
Only catch HomeAssistantError and vol.Invalid
Shulyaka May 17, 2024
a8f0445
Add config flow option
balloob May 18, 2024
3c2cd07
Fix type
balloob May 18, 2024
68d7c8f
Add translation
balloob May 18, 2024
c9f9385
Allow changing API access from options flow
balloob May 18, 2024
e3fd6de
Allow model picking
balloob May 18, 2024
2aaed5b
Remove allowing HASS Access in main flow
balloob May 18, 2024
d71fca7
Move model to the top in options flow
balloob May 18, 2024
a98e801
Make prompt conditional based on API access
balloob May 18, 2024
cf2b230
convert only once to dict
balloob May 18, 2024
56c5e99
Reduce debug logging
balloob May 18, 2024
cb4f0e1
Update title
balloob May 18, 2024
6f39352
re-order models
balloob May 18, 2024
fa81db5
Address comments
balloob May 18, 2024
01e57ee
Move things
balloob May 18, 2024
0ae2f2b
Update labels
balloob May 18, 2024
b076a2d
Add tool call tests
Shulyaka May 18, 2024
d582426
Merge branch 'dev' into google_ai_tools
Shulyaka May 18, 2024
b8f2db9
coverage
Shulyaka May 18, 2024
5358aaa
Merge remote-tracking branch 'origin/dev' into google_ai_tools
balloob May 19, 2024
581d6d0
Use LLM APIs
balloob May 19, 2024
f59fa45
Fixes
balloob May 19, 2024
40d927f
Address comments
balloob May 20, 2024
7b49680
Reinstate the title to not break entity name
balloob May 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.typing import ConfigType

from .const import CONF_CHAT_MODEL, CONF_PROMPT, DEFAULT_CHAT_MODEL, DOMAIN, LOGGER
from .const import CONF_PROMPT, DEFAULT_CHAT_MODEL, DOMAIN, LOGGER

SERVICE_GENERATE_CONTENT = "generate_content"
CONF_IMAGE_FILENAME = "image_filename"
Expand Down Expand Up @@ -97,11 +97,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
genai.configure(api_key=entry.data[CONF_API_KEY])

try:
await hass.async_add_executor_job(
partial(
genai.get_model, entry.options.get(CONF_CHAT_MODEL, DEFAULT_CHAT_MODEL)
)
)
await hass.async_add_executor_job(partial(genai.get_model, DEFAULT_CHAT_MODEL))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this because when I had configured a bad model, the config entry refused to startup

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is that bad? Isn't it better to fail as soon as possible?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The config entry wouldn't set up and the user couldn't change the model anymore 🙈

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(happened to me)

except ClientError as err:
if err.reason == "API_KEY_INVALID":
LOGGER.error("Invalid API key: %s", err)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

from functools import partial
import logging
import types
from types import MappingProxyType
from typing import Any

Expand All @@ -18,11 +17,14 @@
ConfigFlowResult,
OptionsFlow,
)
from homeassistant.const import CONF_API_KEY
from homeassistant.const import CONF_ALLOW_HASS_ACCESS, CONF_API_KEY
from homeassistant.core import HomeAssistant
from homeassistant.helpers.selector import (
NumberSelector,
NumberSelectorConfig,
SelectOptionDict,
SelectSelector,
SelectSelectorConfig,
TemplateSelector,
)

Expand All @@ -33,6 +35,7 @@
CONF_TEMPERATURE,
CONF_TOP_K,
CONF_TOP_P,
DEFAULT_ALLOW_HASS_ACCESS,
DEFAULT_CHAT_MODEL,
DEFAULT_MAX_TOKENS,
DEFAULT_PROMPT,
Expand All @@ -50,17 +53,6 @@
}
)

DEFAULT_OPTIONS = types.MappingProxyType(
{
CONF_PROMPT: DEFAULT_PROMPT,
CONF_CHAT_MODEL: DEFAULT_CHAT_MODEL,
CONF_TEMPERATURE: DEFAULT_TEMPERATURE,
CONF_TOP_P: DEFAULT_TOP_P,
CONF_TOP_K: DEFAULT_TOP_K,
CONF_MAX_TOKENS: DEFAULT_MAX_TOKENS,
}
)


async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> None:
"""Validate the user input allows us to connect.
Expand Down Expand Up @@ -99,7 +91,8 @@ async def async_step_user(
errors["base"] = "unknown"
else:
return self.async_create_entry(
title="Google Generative AI Conversation", data=user_input
title="",
data=user_input,
)

return self.async_show_form(
Expand All @@ -126,53 +119,67 @@ async def async_step_init(
) -> ConfigFlowResult:
"""Manage the options."""
if user_input is not None:
return self.async_create_entry(
title="Google Generative AI Conversation", data=user_input
)
schema = google_generative_ai_config_option_schema(self.config_entry.options)
return self.async_create_entry(title="", data=user_input)
schema = await google_generative_ai_config_option_schema(
self.hass, self.config_entry.options
)
return self.async_show_form(
step_id="init",
data_schema=vol.Schema(schema),
)


def google_generative_ai_config_option_schema(
async def google_generative_ai_config_option_schema(
hass: HomeAssistant,
options: MappingProxyType[str, Any],
) -> dict:
"""Return a schema for Google Generative AI completion options."""
if not options:
options = DEFAULT_OPTIONS
models = await hass.async_add_executor_job(partial(genai.list_models))
return {
vol.Optional(
CONF_CHAT_MODEL,
description={"suggested_value": options.get(CONF_CHAT_MODEL)},
default=DEFAULT_CHAT_MODEL,
): SelectSelector(
SelectSelectorConfig(
options=[
SelectOptionDict(
label=model.display_name,
value=model.name,
)
for model in models
if "generateContent" in model.supported_generation_methods
]
)
),
vol.Optional(
CONF_ALLOW_HASS_ACCESS,
description={"suggested_value": options.get(CONF_ALLOW_HASS_ACCESS)},
default=DEFAULT_ALLOW_HASS_ACCESS,
): bool,
vol.Optional(
CONF_PROMPT,
description={"suggested_value": options[CONF_PROMPT]},
description={"suggested_value": options.get(CONF_PROMPT)},
default=DEFAULT_PROMPT,
): TemplateSelector(),
vol.Optional(
CONF_CHAT_MODEL,
description={
"suggested_value": options.get(CONF_CHAT_MODEL, DEFAULT_CHAT_MODEL)
},
default=DEFAULT_CHAT_MODEL,
): str,
vol.Optional(
CONF_TEMPERATURE,
description={"suggested_value": options[CONF_TEMPERATURE]},
description={"suggested_value": options.get(CONF_TEMPERATURE)},
default=DEFAULT_TEMPERATURE,
): NumberSelector(NumberSelectorConfig(min=0, max=1, step=0.05)),
vol.Optional(
CONF_TOP_P,
description={"suggested_value": options[CONF_TOP_P]},
description={"suggested_value": options.get(CONF_TOP_P)},
default=DEFAULT_TOP_P,
): NumberSelector(NumberSelectorConfig(min=0, max=1, step=0.05)),
vol.Optional(
CONF_TOP_K,
description={"suggested_value": options[CONF_TOP_K]},
description={"suggested_value": options.get(CONF_TOP_K)},
default=DEFAULT_TOP_K,
): int,
vol.Optional(
CONF_MAX_TOKENS,
description={"suggested_value": options[CONF_MAX_TOKENS]},
description={"suggested_value": options.get(CONF_MAX_TOKENS)},
default=DEFAULT_MAX_TOKENS,
): int,
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@
{%- endif %}
{%- endfor %}
{%- endfor %}
"""

Answer the user's questions about the world truthfully.

If the user wants to control a device, reject the request and suggest using the Home Assistant app.
PROMPT_NO_HASS_ACCESS = "If the user wants to control a device, tell them to enable Home Assistant access for the Google configuration."
PROMPT_HASS_ACCESS = """
Call the intent tools to control the system. Just pass the name to the intent.
"""

CONF_CHAT_MODEL = "chat_model"
DEFAULT_CHAT_MODEL = "models/gemini-pro"
CONF_TEMPERATURE = "temperature"
Expand All @@ -36,3 +38,4 @@
DEFAULT_TOP_K = 1
CONF_MAX_TOKENS = "max_tokens"
DEFAULT_MAX_TOKENS = 150
DEFAULT_ALLOW_HASS_ACCESS = False
Loading
Loading