voice: усиление умного дома — контекст, промпт, новые tools
All checks were successful
Deploy / deploy (push) Successful in 1m52s

- промпт: перечислены ВСЕ 15+ tools, разрешено уверенно управлять домом
- route.ts: живой контекст (время + снимок устройств из HA) в системный промпт
  для LLM-пути (defensive, с таймаутом)
- новые tools: control_climate (кондей/термостат), control_tv, set_scene
  (night/movie/morning/away), all_off, ha_service (универсальный HA с whitelist)
- env: CLIMATE_ENTITY, TV_ENTITY (см. RUNBOOK)
This commit is contained in:
d.klimov
2026-07-22 23:49:50 +03:00
parent 218a7a3acb
commit be0a731738
8 changed files with 395 additions and 8 deletions

71
lib/tools/climate.ts Normal file
View File

@@ -0,0 +1,71 @@
import type { VoiceTool } from './_types'
import { tabletJson } from './_http'
/**
* Кондиционер / термостат через Home Assistant (домен climate).
* Entity задаётся CLIMATE_ENTITY (по умолчанию climate.thermostat).
*/
const ENTITY = () => process.env.CLIMATE_ENTITY || 'climate.thermostat'
const HVAC: Record<string, string> = {
heat: 'heat', 'тепло': 'heat', 'нагрев': 'heat', 'обогрев': 'heat',
cool: 'cool', 'холод': 'cool', 'охлаждение': 'cool', 'прохлада': 'cool',
auto: 'auto', 'авто': 'auto',
off: 'off', 'выкл': 'off',
}
const controlClimate: VoiceTool = {
schema: {
type: 'function',
function: {
name: 'control_climate',
description:
'Управление кондиционером/термостатом: задать температуру, режим или включить/выключить. ' +
'Используй для «сделай теплее/прохладнее», «поставь 22 градуса», «включи кондиционер», ' +
'«режим охлаждения».',
parameters: {
type: 'object',
properties: {
action: {
type: 'string',
enum: ['set_temperature', 'set_mode', 'turn_on', 'turn_off'],
description: 'Что сделать',
},
temperature: {
type: 'number',
description: 'Целевая температура °C при action=set_temperature (16-30)',
},
mode: {
type: 'string',
description: 'Режим при action=set_mode: heat, cool, auto, off',
},
},
required: ['action'],
},
},
},
async execute(args) {
const action = String(args?.action || '')
const entity_id = ENTITY()
let payload: Record<string, any>
if (action === 'set_temperature') {
const t = Number(args?.temperature)
if (!Number.isFinite(t)) return { error: 'temperature required' }
payload = { domain: 'climate', service: 'set_temperature', entity_id, temperature: Math.max(16, Math.min(30, Math.round(t))) }
} else if (action === 'set_mode') {
const hvac = HVAC[String(args?.mode || '').toLowerCase().trim()] || 'auto'
payload = { domain: 'climate', service: 'set_hvac_mode', entity_id, hvac_mode: hvac }
} else if (action === 'turn_on' || action === 'turn_off') {
payload = { domain: 'climate', service: action, entity_id }
} else {
return { error: `unknown action: ${action}` }
}
await tabletJson('POST', '/api/voice/tools/smart-home', payload)
return { success: true, action, ...(payload.temperature ? { temperature: payload.temperature } : {}), ...(payload.hvac_mode ? { mode: payload.hvac_mode } : {}) }
},
}
export const tools: VoiceTool[] = [controlClimate]