Add conversation agent selector (#16212

* Add conversation agent selector

* Add default option

* Update ha-conversation-agent-picker.ts

* Update ha-conversation-agent-picker.ts
This commit is contained in:
Bram Kragten 2023-04-17 20:54:30 +02:00 committed by GitHub
parent ac1e6b87ae
commit bf70427760
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 183 additions and 3 deletions

View File

@ -0,0 +1,109 @@
import {
css,
CSSResultGroup,
html,
LitElement,
nothing,
PropertyValueMap,
} from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event";
import { stopPropagation } from "../common/dom/stop_propagation";
import { Agent, listAgents } from "../data/conversation";
import { HomeAssistant } from "../types";
import "./ha-list-item";
import "./ha-select";
import type { HaSelect } from "./ha-select";
const DEFAULT = "default_agent_option";
@customElement("ha-conversation-agent-picker")
export class HaConversationAgentPicker extends LitElement {
@property() public value?: string;
@property() public label?: string;
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ type: Boolean, reflect: true }) public disabled = false;
@property({ type: Boolean }) public required = false;
@state() _agents?: Agent[];
@state() _defaultAgent: string | null = null;
protected render() {
if (!this._agents) {
return nothing;
}
const value = this.value ?? DEFAULT;
return html`
<ha-select
.label=${this.label ||
this.hass!.localize(
"ui.components.coversation-agent-picker.conversation_agent"
)}
.value=${value}
.required=${this.required}
.disabled=${this.disabled}
@selected=${this._changed}
@closed=${stopPropagation}
fixedMenuPosition
naturalMenuWidth
>
<ha-list-item .value=${DEFAULT}>
${this.hass!.localize(
"ui.components.coversation-agent-picker.default",
{
default: this._agents.find(
(agent) => agent.id === this._defaultAgent
)?.name,
}
)}
</ha-list-item>
${this._agents.map(
(agent) =>
html`<ha-list-item .value=${agent.id}>${agent.name}</ha-list-item>`
)}
</ha-select>
`;
}
protected firstUpdated(
changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>
): void {
super.firstUpdated(changedProperties);
listAgents(this.hass).then((agents) => {
this._agents = agents.agents;
this._defaultAgent = agents.default_agent;
});
}
static get styles(): CSSResultGroup {
return css`
ha-select {
width: 100%;
}
`;
}
private _changed(ev): void {
const target = ev.target as HaSelect;
if (
!this.hass ||
target.value === "" ||
target.value === this.value ||
(this.value === undefined && target.value === DEFAULT)
) {
return;
}
this.value = target.value === DEFAULT ? undefined : target.value;
fireEvent(this, "value-changed", { value: this.value });
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-conversation-agent-picker": HaConversationAgentPicker;
}
}

View File

@ -0,0 +1,45 @@
import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import { ConversationAgentSelector } from "../../data/selector";
import { HomeAssistant } from "../../types";
import "../ha-conversation-agent-picker";
@customElement("ha-selector-conversation_agent")
export class HaConversationAgentSelector extends LitElement {
@property() public hass!: HomeAssistant;
@property() public selector!: ConversationAgentSelector;
@property() public value?: any;
@property() public label?: string;
@property() public helper?: string;
@property({ type: Boolean }) public disabled = false;
@property({ type: Boolean }) public required = true;
protected render() {
return html`<ha-conversation-agent-picker
.hass=${this.hass}
.value=${this.value}
.label=${this.label}
.helper=${this.helper}
.disabled=${this.disabled}
.required=${this.required}
></ha-conversation-agent-picker>`;
}
static styles = css`
ha-conversation-agent-picker {
width: 100%;
}
`;
}
declare global {
interface HTMLElementTagNameMap {
"ha-selector-conversation_agent": HaConversationAgentSelector;
}
}

View File

@ -17,6 +17,7 @@ const LOAD_ELEMENTS = {
boolean: () => import("./ha-selector-boolean"),
color_rgb: () => import("./ha-selector-color-rgb"),
config_entry: () => import("./ha-selector-config-entry"),
conversation_agent: () => import("./ha-selector-conversation-agent"),
constant: () => import("./ha-selector-constant"),
date: () => import("./ha-selector-date"),
datetime: () => import("./ha-selector-datetime"),

View File

@ -1,4 +1,3 @@
import "@material/mwc-button";
import "@material/mwc-list/mwc-list-item";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";

View File

@ -56,6 +56,11 @@ export interface AgentInfo {
attribution?: { name: string; url: string };
}
export interface Agent {
id: string;
name: string;
}
export const processConversationInput = (
hass: HomeAssistant,
text: string,
@ -70,9 +75,20 @@ export const processConversationInput = (
language,
});
export const getAgentInfo = (hass: HomeAssistant): Promise<AgentInfo> =>
export const listAgents = (
hass: HomeAssistant
): Promise<{ agents: Agent[]; default_agent: string | null }> =>
hass.callWS({
type: "conversation/agent/list",
});
export const getAgentInfo = (
hass: HomeAssistant,
agent_id?: string
): Promise<AgentInfo> =>
hass.callWS({
type: "conversation/agent/info",
agent_id,
});
export const prepareConversation = (

View File

@ -14,6 +14,7 @@ export type Selector =
| BooleanSelector
| ColorRGBSelector
| ColorTempSelector
| ConversationAgentSelector
| ConfigEntrySelector
| ConstantSelector
| DateSelector
@ -85,6 +86,11 @@ export interface ColorTempSelector {
} | null;
}
export interface ConversationAgentSelector {
// eslint-disable-next-line @typescript-eslint/ban-types
conversation_agent: {} | null;
}
export interface ConfigEntrySelector {
config_entry: {
integration?: string;

View File

@ -125,7 +125,7 @@ export class DialogVoiceAssistantPipelineDetail extends LitElement {
name: "conversation_engine",
required: true,
selector: {
text: {},
conversation_agent: {},
},
},
{

View File

@ -401,6 +401,10 @@
"config-entry-picker": {
"config_entry": "Integration"
},
"coversation-agent-picker": {
"conversation_agent": "Conversation agent",
"default": "Default agent ({default})"
},
"theme-picker": {
"theme": "Theme",
"no_theme": "No theme"