// home-assistant's tools — its own code (novox/hq ADR 0039), importing its own client. They return // structured data; the mesh serves them through the sdk's tool harness. import { registerModuleTools, type ToolDefinition } from "@novox/mesh-sdk/tools"; import { HomeAssistantClient, type HAEntityState } from "../client.js"; /** Trim an entity to the fields worth returning — the full attribute bag is large and mostly noise. */ function summarize(s: HAEntityState): { entity_id: string; state: string; name?: string; last_changed?: string } { return { entity_id: s.entity_id, state: s.state, name: typeof s.attributes.friendly_name === "string" ? s.attributes.friendly_name : undefined, last_changed: s.last_changed, }; } export function getHomeAssistantTools(ha: HomeAssistantClient): ToolDefinition[] { return [ { name: "homeassistant_states", description: "Entity states from Home Assistant. With no argument, lists every entity; with `entity` (e.g. light.kitchen), returns just that one with its full attributes.", input: { entity: { type: "string", description: "an entity id to fetch one entity; omitted lists all" } }, run: async (args) => { if (args.entity) { const s = await ha.getState(String(args.entity)); return { entity_id: s.entity_id, state: s.state, attributes: s.attributes, last_changed: s.last_changed }; } const states = await ha.getStates(); return { count: states.length, entities: states.map(summarize) }; }, }, { name: "homeassistant_call_service", description: "Call a Home Assistant service — turn a switch/light on or off, lock a door, etc. Give the domain (e.g. switch), the service (e.g. turn_on), and optionally a target entity and extra data.", input: { domain: { type: "string", description: "the service domain, e.g. light, switch, lock" }, service: { type: "string", description: "the service, e.g. turn_on, turn_off, toggle" }, entity: { type: "string", description: "the entity id to target (optional)" }, data: { type: "object", description: "extra service data merged into the call (optional)" }, }, run: async (args) => { const data: Record = { ...(args.data as Record | undefined) }; if (args.entity) data.entity_id = String(args.entity); const changed = await ha.callService(String(args.domain), String(args.service), data); return { changed: changed.map(summarize) }; }, }, { name: "homeassistant_config", description: "Home Assistant instance config: version, location, timezone, loaded components.", input: {}, run: async () => { const c = await ha.getConfig(); return { location: c.location_name, version: c.version, time_zone: c.time_zone, state: c.state, components: c.components?.length ?? 0, }; }, }, ]; } // The tools exist only when a token is configured; without one, home-assistant contributes none // rather than failing the whole runtime. registerModuleTools("home-assistant", (env) => { try { return getHomeAssistantTools(HomeAssistantClient.fromEnv(env)); } catch { return []; } });