- create_event(title, date, start_time?, end_time?, all_day?, owner)
owner обязателен (daniil | sveta). System prompt велит LLM уточнять
чей это календарь, если неясно.
- update_event(event_id, owner, ...fields) — меняет только переданные
поля. Сначала нужно вызвать get_today_events для получения event_id.
- delete_event(event_id, owner) — сначала get_today_events, найти
событие по названию, подтвердить если важное.
get_today_events теперь возвращает event_id и owner (daniil/sveta),
плюс принимает range=month. Description явно говорит LLM что это
первый tool для CRUD-сценариев.
System prompt (Cosmo и Люся) дополнен секцией 'Работа с календарём'
с правилами: даты YYYY-MM-DD, время HH:MM, «завтра» = +1 день,
вычислять от {today}.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bug: Claude hallucinated actions. User said «удалить таймер чайника»,
Claude replied «Таймер чайника отменён» без вызова cancel_timer.
Две причины:
1) История сохраняла только финальный текст предыдущих turn'ов.
Claude видел «я говорил поставил таймер» и мог ответить «удалил» по
паттерну без реального tool-use.
2) System prompt мягко просил использовать tools — Haiku иногда
пропускал tool и отвечал сразу.
Фикс:
- История теперь содержит полные turn'ы (assistant с tool_use блоками,
user с tool_result блоками). _build_messages/_strip_cache_control
корректно обрабатывают content как string или list of blocks.
- System prompt добавил жёсткий раздел «ЖЁСТКИЕ ПРАВИЛА про tools»:
явно запрещено говорить 'поставил/отменил/удалил' без вызова tool,
информацию (погода, события) — только через tool, не выдумывать.
Размер истории вырастет (tool_result'ы могут быть по 500-2000 байт),
но это не проблема — prompt caching делает каждый turn дешёвым на
чтение (cache_r > 90% в логах).
После ответа Python сразу уходит в record() ждать follow-up
(FOLLOWUP_TIMEOUT), но планшет об этом не знал — оверлей тихо
скрывался и пользователю казалось что Cosmo его не слышит без
повторного wake-word.
Теперь между итерациями _conversation_loop шлётся notifier.listening() —
планшет показывает мягко пульсирующий орб с 'жду' + сохранённым
текстом прошлого ответа. Закрывается только по notifier.idle()
(таймаут тишины) или если пользователь что-то сказал (command).
Two new Claude tools for voice control over existing timers.
Both accept a {label} (fuzzy match on tablet side, case-insensitive
substring) so the LLM doesn'\''t need to know internal timer ids.
- cancel_timer(label) → POST /api/voice/timer {action:cancel}
- adjust_timer(label, delta_seconds) → POST {action:adjust}
Use cases:
'\''Отмени таймер чайник'\'' → cancel_timer(label="чайник")
'\''Добавь ещё 5 минут к пасте'\'' → adjust_timer(label="паста", delta_seconds=300)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Claude Haiku 4.5 теперь умеет дёргать tools. Все tools — proxy к endpoints
планшета (/api/voice/tools/* и /api/voice/timer) с bearer auth
VOICE_API_KEY. Никакой дополнительной auth в скрипте не требуется.
- satellite/tools.py — 5 tools:
* get_weather(city?) → Open-Meteo через tablet
* get_transport(direction, routes?) → трамваи Антонова-Овсеенко
* get_today_events(range?) → Google Calendar (today/week)
* get_notes() → текстовые + shopping lists
* set_timer(seconds, label) → создаёт таймер на дашборде
Каждый tool возвращает dict/list; ошибки упаковываются как {error: ...}
и отдаются Claude как результат — он сам обрабатывает.
- satellite/llm_claude.py:
* Подключил TOOL_SCHEMAS в вызов messages.create
* Цикл tool-use: до MAX_TOOL_ROUNDS=4 раундов tool_use → exec → tool_result
* System prompt дополнен инструкцией «используй tools без спроса»
* Финальный текст (после всех tool rounds) сохраняется в историю как один
assistant-turn — tool rounds в history не пишутся чтобы не раздувать кеш
* Usage логируется суммарно за все раунды
Работает с уже поднятым tinyproxy на .103 (HTTPS_PROXY в .env).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Allows removing all GATEWAY_*, VOICE_MODEL, *_SESSION_KEY env vars
when running on the Claude direct backend. The OpenClaw hard-exit
check now only fires when that backend is actually selected.
Adds a parallel LLM backend that bypasses OpenClaw and talks to
Anthropic Messages API directly. Selected via LLM_BACKEND=claude in
.env; default remains openclaw so nothing breaks for existing setup.
Why: OpenClaw gateway adds 500-1000ms overhead on every turn (auth,
memory fetch, routing). Direct Haiku 4.5 + prompt caching = faster
first token and -90% cost on cached chunks.
- satellite/llm_claude.py — Anthropic SDK streaming client, prompt
caching on system prompt and all-but-last-2 history messages, per
agent+date JSON history in HISTORY_DIR, reset_history() for the
'сбрось' command, per-agent system prompts (Cosmo / Люся), fallback
to error event if SDK/key missing.
- satellite/llm.py — dispatches to ask_claude_stream when backend=claude,
exports LLM_BACKEND so modes.py can route reset too.
- satellite/modes.py — _handle_reset calls reset_history when backend
is claude, keeps /new POST for openclaw.
- requirements.txt — anthropic >= 0.50.0
- .env.example — LLM_BACKEND, ANTHROPIC_API_KEY, ANTHROPIC_MODEL,
HISTORY_DIR, MAX_HISTORY, HTTPS_PROXY block for non-RU egress.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When TABLET_URL and VOICE_API_KEY are set, the tablet handles TTS
via its ElevenLabs proxy — local speak() is skipped. Controlled
by TABLET_TTS_ENABLED (default true when tablet is configured).
- notifier.speak_locally() — gate used by all local speech paths
- llm._maybe_speak — no-op when tablet plays the voice
- modes._handle_reset — emits response event and skips local speak
when tablet TTS is on; keeps spoken fallback otherwise
Tablet side in smart-home-tablet repo: /api/voice/tts endpoint +
VoiceOverlay audio playback (commit ba2e… pending).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a thin HTTP bridge so the tablet at https://tablet.digital-home.site
shows a Siri-style overlay reflecting the current assistant state
(wake / command / response / idle / error). Non-fatal: if the tablet
is offline or TABLET_URL/VOICE_API_KEY are unset, events are silently
skipped and the assistant keeps working.
- satellite/notifier.py — POST /api/voice/event with bearer token,
reused requests.Session for keep-alive, 1.5s timeout
- satellite/modes.py — emits wake on activation, command after STT,
response after LLM, idle on timeout
- satellite/llm.py — emits error on gateway connection/timeout/HTTP
- .env.example documents TABLET_URL and VOICE_API_KEY
Tablet side (separate repo smart-home-tablet, commit 51c3d60) exposes
POST /api/voice/event + GET /api/voice/stream (SSE) and renders a
full-screen overlay in components/VoiceOverlay.tsx.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- audio: switch VAD to webrtcvad with RMS gate + fallback to RMS
- audio: honor FOLLOWUP_TIMEOUT — short silence wait after bot response
- llm: retry with exponential backoff on network errors and 5xx
- llm: VOICE_MAX_TOKENS env (default 300) instead of hardcoded 150
- tts: optional VAD-based barge-in (BARGE_IN_ENABLED, off by default)
- tts: remove dead start_barge_in_listener / was_barge_in helpers
- config: drop AGENT/LUSYA_AGENT — routing happens via session_key
- modes: remove unused imports, pass FOLLOWUP_TIMEOUT to follow-up record()
- docs: full rewrite of README and CLAUDE.md to match current architecture
- Remove local Conversation history (now managed by gateway)
- Use x-openclaw-session-key for persistent agent sessions
- Agent now has full context: SOUL.md, MEMORY.md, tools
- Add VOICE_SESSION_KEY env var (default: agent:main:voice:home)
- Backward compatible: conv parameter kept for compatibility
- Add training/ pipeline (step_1..step_5) and own-samples flow
- record_wav.py with single-shot and long-record modes, RMS-based silence filter
- remove_silent.py to drop silent samples and renumber
- modes.py: openwakeword inference with reset() and quiet predictions; commented Lusya block for later
- stt.py: drop local faster-whisper fallback, Groq-only
- config.py: remove unused STT_PROVIDER/WHISPER_*
- llm.py: replace __import__("os") hack with proper import
- tts.py: remove debug traceback in play_error_sound
- requirements.txt: add openwakeword/sounddevice/scipy, drop faster-whisper
- deploy/setup.sh: validate ELEVENLABS_API_KEY and WAKE_WORD_COSMO presence
- README.md, CLAUDE.md, project_roadmap memory updated to reflect new architecture