refactor: optimize configuration and tool implementations
- Standardized error handling across tool implementations - Improved return type consistency for tool execution results - Simplified configuration parsing and type definitions - Enhanced type safety for various configuration schemas - Cleaned up and normalized tool response structures - Updated SSE and event subscription tool implementations
This commit is contained in:
@@ -1,268 +1,292 @@
|
||||
import { JSONSchemaType } from 'ajv';
|
||||
import { Entity, StateChangedEvent } from '../types/hass.js';
|
||||
import { JSONSchemaType } from "ajv";
|
||||
import { Entity, StateChangedEvent } from "../types/hass.js";
|
||||
|
||||
// Define base types for automation components
|
||||
type TriggerType = {
|
||||
platform: string;
|
||||
event?: string | null;
|
||||
entity_id?: string | null;
|
||||
to?: string | null;
|
||||
from?: string | null;
|
||||
offset?: string | null;
|
||||
[key: string]: any;
|
||||
platform: string;
|
||||
event?: string | null;
|
||||
entity_id?: string | null;
|
||||
to?: string | null;
|
||||
from?: string | null;
|
||||
offset?: string | null;
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
type ConditionType = {
|
||||
condition: string;
|
||||
conditions?: Array<Record<string, any>> | null;
|
||||
[key: string]: any;
|
||||
condition: string;
|
||||
conditions?: Array<Record<string, any>> | null;
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
type ActionType = {
|
||||
service: string;
|
||||
target?: {
|
||||
entity_id?: string | string[] | null;
|
||||
[key: string]: any;
|
||||
} | null;
|
||||
data?: Record<string, any> | null;
|
||||
service: string;
|
||||
target?: {
|
||||
entity_id?: string | string[] | null;
|
||||
[key: string]: any;
|
||||
} | null;
|
||||
data?: Record<string, any> | null;
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
type AutomationType = {
|
||||
alias: string;
|
||||
description?: string | null;
|
||||
mode?: ('single' | 'parallel' | 'queued' | 'restart') | null;
|
||||
trigger: TriggerType[];
|
||||
condition?: ConditionType[] | null;
|
||||
action: ActionType[];
|
||||
alias: string;
|
||||
description?: string | null;
|
||||
mode?: ("single" | "parallel" | "queued" | "restart") | null;
|
||||
trigger: TriggerType[];
|
||||
condition?: ConditionType[] | null;
|
||||
action: ActionType[];
|
||||
};
|
||||
|
||||
type DeviceControlType = {
|
||||
domain: 'light' | 'switch' | 'climate' | 'cover' | 'fan' | 'scene' | 'script' | 'media_player';
|
||||
command: string;
|
||||
entity_id: string | string[];
|
||||
parameters?: Record<string, any> | null;
|
||||
domain:
|
||||
| "light"
|
||||
| "switch"
|
||||
| "climate"
|
||||
| "cover"
|
||||
| "fan"
|
||||
| "scene"
|
||||
| "script"
|
||||
| "media_player";
|
||||
command: string;
|
||||
entity_id: string | string[];
|
||||
parameters?: Record<string, any> | null;
|
||||
};
|
||||
|
||||
// Define missing types
|
||||
export interface Service {
|
||||
name: string;
|
||||
description: string;
|
||||
target?: {
|
||||
entity?: string[];
|
||||
device?: string[];
|
||||
area?: string[];
|
||||
} | null;
|
||||
fields: Record<string, any>;
|
||||
name: string;
|
||||
description: string;
|
||||
target?: {
|
||||
entity?: string[];
|
||||
device?: string[];
|
||||
area?: string[];
|
||||
} | null;
|
||||
fields: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface Config {
|
||||
components: string[];
|
||||
config_dir: string;
|
||||
elevation: number;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
location_name: string;
|
||||
time_zone: string;
|
||||
unit_system: {
|
||||
length: string;
|
||||
mass: string;
|
||||
temperature: string;
|
||||
volume: string;
|
||||
};
|
||||
version: string;
|
||||
components: string[];
|
||||
config_dir: string;
|
||||
elevation: number;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
location_name: string;
|
||||
time_zone: string;
|
||||
unit_system: {
|
||||
length: string;
|
||||
mass: string;
|
||||
temperature: string;
|
||||
volume: string;
|
||||
};
|
||||
version: string;
|
||||
}
|
||||
|
||||
// Define base schemas
|
||||
const contextSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
parent_id: { type: 'string', nullable: true },
|
||||
user_id: { type: 'string', nullable: true }
|
||||
},
|
||||
required: ['id', 'parent_id', 'user_id'],
|
||||
additionalProperties: false
|
||||
type: "object",
|
||||
properties: {
|
||||
id: { type: "string" },
|
||||
parent_id: { type: "string", nullable: true },
|
||||
user_id: { type: "string", nullable: true },
|
||||
},
|
||||
required: ["id", "parent_id", "user_id"],
|
||||
additionalProperties: false,
|
||||
} as const;
|
||||
|
||||
// Entity schema
|
||||
export const entitySchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
entity_id: { type: 'string' },
|
||||
state: { type: 'string' },
|
||||
attributes: {
|
||||
type: 'object',
|
||||
additionalProperties: true
|
||||
},
|
||||
last_changed: { type: 'string' },
|
||||
last_updated: { type: 'string' },
|
||||
context: contextSchema
|
||||
type: "object",
|
||||
properties: {
|
||||
entity_id: { type: "string" },
|
||||
state: { type: "string" },
|
||||
attributes: {
|
||||
type: "object",
|
||||
additionalProperties: true,
|
||||
},
|
||||
required: ['entity_id', 'state', 'attributes', 'last_changed', 'last_updated', 'context'],
|
||||
additionalProperties: false
|
||||
last_changed: { type: "string" },
|
||||
last_updated: { type: "string" },
|
||||
context: contextSchema,
|
||||
},
|
||||
required: [
|
||||
"entity_id",
|
||||
"state",
|
||||
"attributes",
|
||||
"last_changed",
|
||||
"last_updated",
|
||||
"context",
|
||||
],
|
||||
additionalProperties: false,
|
||||
} as const;
|
||||
|
||||
// Service schema
|
||||
export const serviceSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
description: { type: 'string' },
|
||||
target: {
|
||||
type: 'object',
|
||||
nullable: true,
|
||||
properties: {
|
||||
entity: { type: 'array', items: { type: 'string' }, nullable: true },
|
||||
device: { type: 'array', items: { type: 'string' }, nullable: true },
|
||||
area: { type: 'array', items: { type: 'string' }, nullable: true }
|
||||
},
|
||||
required: [],
|
||||
additionalProperties: false
|
||||
},
|
||||
fields: {
|
||||
type: 'object',
|
||||
additionalProperties: true
|
||||
}
|
||||
type: "object",
|
||||
properties: {
|
||||
name: { type: "string" },
|
||||
description: { type: "string" },
|
||||
target: {
|
||||
type: "object",
|
||||
nullable: true,
|
||||
properties: {
|
||||
entity: { type: "array", items: { type: "string" }, nullable: true },
|
||||
device: { type: "array", items: { type: "string" }, nullable: true },
|
||||
area: { type: "array", items: { type: "string" }, nullable: true },
|
||||
},
|
||||
required: [],
|
||||
additionalProperties: false,
|
||||
},
|
||||
required: ['name', 'description', 'fields'],
|
||||
additionalProperties: false
|
||||
fields: {
|
||||
type: "object",
|
||||
additionalProperties: true,
|
||||
},
|
||||
},
|
||||
required: ["name", "description", "fields"],
|
||||
additionalProperties: false,
|
||||
} as const;
|
||||
|
||||
// Define the trigger schema without type assertion
|
||||
export const triggerSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
platform: { type: 'string' },
|
||||
event: { type: 'string', nullable: true },
|
||||
entity_id: { type: 'string', nullable: true },
|
||||
to: { type: 'string', nullable: true },
|
||||
from: { type: 'string', nullable: true },
|
||||
offset: { type: 'string', nullable: true }
|
||||
},
|
||||
required: ['platform'],
|
||||
additionalProperties: true
|
||||
type: "object",
|
||||
properties: {
|
||||
platform: { type: "string" },
|
||||
event: { type: "string", nullable: true },
|
||||
entity_id: { type: "string", nullable: true },
|
||||
to: { type: "string", nullable: true },
|
||||
from: { type: "string", nullable: true },
|
||||
offset: { type: "string", nullable: true },
|
||||
},
|
||||
required: ["platform"],
|
||||
additionalProperties: true,
|
||||
};
|
||||
|
||||
// Define the automation schema
|
||||
export const automationSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
alias: { type: 'string' },
|
||||
description: { type: 'string', nullable: true },
|
||||
mode: {
|
||||
type: 'string',
|
||||
enum: ['single', 'parallel', 'queued', 'restart'],
|
||||
nullable: true
|
||||
},
|
||||
trigger: {
|
||||
type: 'array',
|
||||
items: triggerSchema
|
||||
},
|
||||
condition: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
additionalProperties: true
|
||||
},
|
||||
nullable: true
|
||||
},
|
||||
action: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
additionalProperties: true
|
||||
}
|
||||
}
|
||||
type: "object",
|
||||
properties: {
|
||||
alias: { type: "string" },
|
||||
description: { type: "string", nullable: true },
|
||||
mode: {
|
||||
type: "string",
|
||||
enum: ["single", "parallel", "queued", "restart"],
|
||||
nullable: true,
|
||||
},
|
||||
required: ['alias', 'trigger', 'action'],
|
||||
additionalProperties: false
|
||||
trigger: {
|
||||
type: "array",
|
||||
items: triggerSchema,
|
||||
},
|
||||
condition: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
additionalProperties: true,
|
||||
},
|
||||
nullable: true,
|
||||
},
|
||||
action: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
additionalProperties: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ["alias", "trigger", "action"],
|
||||
additionalProperties: false,
|
||||
};
|
||||
|
||||
export const deviceControlSchema: JSONSchemaType<DeviceControlType> = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
domain: {
|
||||
type: 'string',
|
||||
enum: ['light', 'switch', 'climate', 'cover', 'fan', 'scene', 'script', 'media_player']
|
||||
},
|
||||
command: { type: 'string' },
|
||||
entity_id: {
|
||||
anyOf: [
|
||||
{ type: 'string' },
|
||||
{
|
||||
type: 'array',
|
||||
items: { type: 'string' }
|
||||
}
|
||||
]
|
||||
},
|
||||
parameters: {
|
||||
type: 'object',
|
||||
nullable: true,
|
||||
additionalProperties: true
|
||||
}
|
||||
type: "object",
|
||||
properties: {
|
||||
domain: {
|
||||
type: "string",
|
||||
enum: [
|
||||
"light",
|
||||
"switch",
|
||||
"climate",
|
||||
"cover",
|
||||
"fan",
|
||||
"scene",
|
||||
"script",
|
||||
"media_player",
|
||||
],
|
||||
},
|
||||
required: ['domain', 'command', 'entity_id'],
|
||||
additionalProperties: false
|
||||
command: { type: "string" },
|
||||
entity_id: {
|
||||
anyOf: [
|
||||
{ type: "string" },
|
||||
{
|
||||
type: "array",
|
||||
items: { type: "string" },
|
||||
},
|
||||
],
|
||||
},
|
||||
parameters: {
|
||||
type: "object",
|
||||
nullable: true,
|
||||
additionalProperties: true,
|
||||
},
|
||||
},
|
||||
required: ["domain", "command", "entity_id"],
|
||||
additionalProperties: false,
|
||||
};
|
||||
|
||||
// State changed event schema
|
||||
export const stateChangedEventSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
event_type: { type: 'string', const: 'state_changed' },
|
||||
data: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
entity_id: { type: 'string' },
|
||||
new_state: { ...entitySchema, nullable: true },
|
||||
old_state: { ...entitySchema, nullable: true }
|
||||
},
|
||||
required: ['entity_id', 'new_state', 'old_state'],
|
||||
additionalProperties: false
|
||||
},
|
||||
origin: { type: 'string' },
|
||||
time_fired: { type: 'string' },
|
||||
context: contextSchema
|
||||
type: "object",
|
||||
properties: {
|
||||
event_type: { type: "string", const: "state_changed" },
|
||||
data: {
|
||||
type: "object",
|
||||
properties: {
|
||||
entity_id: { type: "string" },
|
||||
new_state: { ...entitySchema, nullable: true },
|
||||
old_state: { ...entitySchema, nullable: true },
|
||||
},
|
||||
required: ["entity_id", "new_state", "old_state"],
|
||||
additionalProperties: false,
|
||||
},
|
||||
required: ['event_type', 'data', 'origin', 'time_fired', 'context'],
|
||||
additionalProperties: false
|
||||
origin: { type: "string" },
|
||||
time_fired: { type: "string" },
|
||||
context: contextSchema,
|
||||
},
|
||||
required: ["event_type", "data", "origin", "time_fired", "context"],
|
||||
additionalProperties: false,
|
||||
} as const;
|
||||
|
||||
// Config schema
|
||||
export const configSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
components: { type: 'array', items: { type: 'string' } },
|
||||
config_dir: { type: 'string' },
|
||||
elevation: { type: 'number' },
|
||||
latitude: { type: 'number' },
|
||||
longitude: { type: 'number' },
|
||||
location_name: { type: 'string' },
|
||||
time_zone: { type: 'string' },
|
||||
unit_system: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
length: { type: 'string' },
|
||||
mass: { type: 'string' },
|
||||
temperature: { type: 'string' },
|
||||
volume: { type: 'string' }
|
||||
},
|
||||
required: ['length', 'mass', 'temperature', 'volume'],
|
||||
additionalProperties: false
|
||||
},
|
||||
version: { type: 'string' }
|
||||
type: "object",
|
||||
properties: {
|
||||
components: { type: "array", items: { type: "string" } },
|
||||
config_dir: { type: "string" },
|
||||
elevation: { type: "number" },
|
||||
latitude: { type: "number" },
|
||||
longitude: { type: "number" },
|
||||
location_name: { type: "string" },
|
||||
time_zone: { type: "string" },
|
||||
unit_system: {
|
||||
type: "object",
|
||||
properties: {
|
||||
length: { type: "string" },
|
||||
mass: { type: "string" },
|
||||
temperature: { type: "string" },
|
||||
volume: { type: "string" },
|
||||
},
|
||||
required: ["length", "mass", "temperature", "volume"],
|
||||
additionalProperties: false,
|
||||
},
|
||||
required: [
|
||||
'components',
|
||||
'config_dir',
|
||||
'elevation',
|
||||
'latitude',
|
||||
'longitude',
|
||||
'location_name',
|
||||
'time_zone',
|
||||
'unit_system',
|
||||
'version'
|
||||
],
|
||||
additionalProperties: false
|
||||
} as const;
|
||||
version: { type: "string" },
|
||||
},
|
||||
required: [
|
||||
"components",
|
||||
"config_dir",
|
||||
"elevation",
|
||||
"latitude",
|
||||
"longitude",
|
||||
"location_name",
|
||||
"time_zone",
|
||||
"unit_system",
|
||||
"version",
|
||||
],
|
||||
additionalProperties: false,
|
||||
} as const;
|
||||
|
||||
Reference in New Issue
Block a user