Files
Bolt-Pet/.env.example
T
themajesticmagician 3ee67cb4d6 feat: Enhance local command handling and introduce local intents
- Refactor `run_local_command` to manage subprocesses more effectively, ensuring child processes are terminated on timeout.
- Introduce `_terminate` function to handle process group termination and capture output.
- Implement `_command_output` to format command results with a character limit.
- Add local intent recognition in `intents.py` to handle commands like "stop", "go to sleep", and "come here" without server interaction.
- Normalize user input to match local intents while stripping filler words.
- Update tests to cover new local intent functionality and ensure proper command handling.
- Enhance speech processing to handle abbreviations and improve spoken output clarity.
2026-08-05 18:31:02 -06:00

234 lines
13 KiB
Bash

# Copy this file to .env and fill in your values.
# ── Bolt server (required) ──────────────────────────────────────────────────
# The same server URL + key desk_client/bolt_desk.py and the Android app use.
# DESK_API_KEY is the master key from the server's own .env, or a per-user
# key minted via the api_key_generate desk marker (see the main repo's
# CLAUDE.md "Per-user API keys" section).
BOLT_SERVER_URL=http://your-server:5002
DESK_API_KEY=
# Unique per machine/install so sessions don't collide. Defaults to
# "pet-<hostname>" if unset.
#DESK_SESSION_ID=pet-my-desktop
# ── Wake word ────────────────────────────────────────────────────────────────
# openWakeWord model trained for "thunderbolt" — thunderbolt.onnx ships in
# the project root next to this file. Point WAKE_MODEL_FILE at a different
# .onnx model to change the phrase (same convention as desk_client's
# WAKE_MODEL_FILE / bolt.onnx in the main repo).
#WAKE_MODEL_FILE=thunderbolt.onnx
#WAKE_WORD_THRESHOLD=0.5
#WAKE_CHECK_INTERVAL_SECONDS=1.2
# ── STT (Deepgram) ──────────────────────────────────────────────────────────
DEEPGRAM_API_KEY=
#DEEPGRAM_MODEL=nova-3
# ── TTS (ElevenLabs) — omit to use offline TTS only ─────────────────────────
ELEVENLABS_API_KEY=
ELEVENLABS_VOICE_ID=
#ELEVENLABS_MODEL_ID=eleven_flash_v2
#TTS_SAMPLE_RATE=24000
# Ask Bolt to use a different voice (or another language) and the server
# picks one from the ElevenLabs voice library and tags the reply with it.
# It only tags one reply, and it can't remember the id afterwards — so the
# pet keeps using that voice until a new one is picked or you choose "Use
# default voice" in the tray. VOICE_STICKY=false makes each pick last for
# exactly the one reply it came with instead.
#VOICE_STICKY=true
# ── Multi-voice dialogue (ElevenLabs Text to Dialogue) ──────────────────────
# Lets Bolt play a short scene in several voices with delivery tags the v3
# model acts on ("[cheerfully] Hello", "[whispering] He is lying"), driven by
# the server through a relayed `dialoguectl` command. Name the cast here —
# "self" always means whatever voice the pet is currently using.
#DIALOGUE=true
#DIALOGUE_MODEL_ID=eleven_v3
#DIALOGUE_VOICES=narrator:9BWtsMINqrJLrRacOk9x,villain:IKne3meq5aSn9XLyUdCD
# ── Self-restart (optional) ─────────────────────────────────────────────────
# `petctl self_restart <why>` lets Bolt reload the pet after editing its own
# code, so he can check the change live. The code is import-checked first, the
# restart waits for the current turn to finish, and the reason is carried
# across so the new process reports back. The guard refuses more than
# SELF_RESTART_MAX restarts within SELF_RESTART_WINDOW_SECONDS.
#SELF_RESTART=true
#SELF_RESTART_MAX=5
#SELF_RESTART_WINDOW_SECONDS=900
# Used instead of ELEVENLABS_MODEL_ID whenever the server picked the voice
# or the reply has non-ASCII in it — the flash_v2 default is English-only.
#ELEVENLABS_MULTILINGUAL_MODEL_ID=eleven_flash_v2_5
# ── Audio devices (optional — leave blank for the system default) ──────────
#MIC_DEVICE=
#SPEAKER_DEVICE=
# ── VAD tuning (optional) ───────────────────────────────────────────────────
#VAD_RMS_THRESHOLD=300
#VAD_SILENCE_END_SEC=1.2
#VAD_MAX_UTTERANCE_SECONDS=15
#VAD_MIN_UTTERANCE_SECONDS=0.4
#VAD_GRACE_SECONDS=4 # how long to wait for you to start talking
# ── Local intents (optional) ────────────────────────────────────────────────
# A short, closed list of things the pet answers itself, with no server round
# trip: "stop", "be quiet", "come here", "go away", "go to sleep", "wake up",
# "say that again", "sit"/"stay", "go for a walk", "use your normal voice".
# Matched whole and exact, and never while you're answering a question Bolt
# asked, so a real request ("stop the docker container") still goes to him.
# Set to false to route absolutely everything through the server.
#LOCAL_INTENTS=true
# ── Follow-up listening (optional) ──────────────────────────────────────────
# When a reply asks you something, the pet keeps listening for your answer
# instead of dropping back to idle and making you say the wake word again.
# FOLLOW_UP_MAX_TURNS caps how many question-and-answer rounds can chain
# without you re-triggering it (0 = no cap) — a stop on runaway loops if the
# server ends every reply with "?" and the mic keeps feeding it noise.
#FOLLOW_UP_LISTEN=true
#FOLLOW_UP_MAX_TURNS=3
#FOLLOW_UP_GRACE_SECONDS=7 # longer than VAD_GRACE_SECONDS: you were asked something
# ── Pet window (optional) ───────────────────────────────────────────────────
#PET_SIZE=160
#PET_START_X=
#PET_START_Y=
#PET_ALWAYS_ON_TOP=true
#IDLE_ANIMATION_FPS=6
# ── Wandering (optional) — the pet strolls to a random spot while idle ───────
#PET_WANDER=true
#PET_WANDER_INTERVAL_SECONDS=45 # average pause between strolls (randomized 0.5x-1.5x)
#PET_WANDER_SPEED=90 # pixels per second
#PET_WANDER_MAX_DISTANCE=600 # cap on a single stroll's length
#PET_WANDER_MARGIN=20 # keep this far off the screen edges
# ── Mouse behaviour (optional) ──────────────────────────────────────────────
# Shaped input = the square window's transparent corners stop eating clicks.
# Click-through = the pet ignores the mouse entirely (control it from the tray).
#PET_SHAPED_INPUT=true
#PET_CLICK_THROUGH=false
#PET_EDGE_SNAP=true
#PET_SNAP_MARGIN=48
# ── Barge-in (optional) — interrupt the pet mid-sentence ────────────────────
# BARGE_IN_MODE decides what counts as an interruption:
# wake — only the wake word cuts playback (default). Background noise,
# coughs and the TV can't stop it mid-sentence.
# energy — any sustained noise above BARGE_IN_RMS_THRESHOLD does. Faster to
# trigger, but interrupts on anything loud. That threshold defaults
# to 4x VAD_RMS_THRESHOLD because the mic also hears the pet's own
# voice out of the speakers; raise it if playback self-interrupts.
#BARGE_IN=true
#BARGE_IN_MODE=wake
#BARGE_IN_RMS_THRESHOLD=1200 # energy mode only
#BARGE_IN_FRAMES=4 # energy mode only
# Wake mode only. Blank tracks the live WAKE_WORD_THRESHOLD (tray tuner);
# set a number to make interrupting harder than waking the pet from idle,
# e.g. if Bolt's own voice occasionally trips the model.
#BARGE_IN_WAKE_THRESHOLD=0.6
# ── Auto-update (optional) ──────────────────────────────────────────────────
# Watches the Gitea releases page for a tag newer than bolt_pet.__version__,
# then `git checkout`s it and restarts — only ever between turns, never
# mid-conversation. Requires the install to be a git clone; a working tree
# with local changes is skipped (never stashed), and any failure after the
# checkout rolls back to the ref that was live before.
#AUTO_UPDATE=true
#UPDATE_REPO_API=https://git.themajesticnetwork.com/api/v1/repos/TheMajesticNetwork/Bolt-Pet
#UPDATE_CHECK_INTERVAL_SECONDS=3600
#UPDATE_GIT_REMOTE=origin
#UPDATE_INSTALL_DEPS=true
# Only needed if the repo is private (a Gitea token with read:repository).
#UPDATE_TOKEN=
# ── Streaming TTS (optional) — starts talking on the first chunk ────────────
#TTS_STREAMING=true
# ── Screen context (optional) ───────────────────────────────────────────────
# Sends the focused window's title along with what you said, so "what's this
# error?" has a referent. Text only — no screenshots leave the machine.
#SCREEN_CONTEXT=true
# ── Monitors (optional) ─────────────────────────────────────────────────────
# Tacks a one-line summary of your screen layout onto each utterance (how
# many, their sizes, which one the pet is standing on) so Bolt can decide to
# `petctl jump 2` without asking what you've got plugged in. Costs nothing —
# the list comes from the UI, nothing is probed per turn.
#MONITOR_CONTEXT=true
# ── Screen text / OCR (optional) ────────────────────────────────────────────
# Lets Bolt read what's actually on a monitor with `petctl read [n|here|all]`
# and use it in his reply. Pull-only — nothing is captured unless he asks,
# and every read is logged.
#
# Needs the extras from requirements.txt plus an OCR engine:
# pip install mss pytesseract && sudo apt install tesseract-ocr
# or, without sudo:
# pip install mss rapidocr-onnxruntime
# mss captures on X11/Windows/macOS but NOT Wayland.
#
# This sends the text of a whole screen to the server when used. That's not a
# new capability — the shell relay could already screenshot and OCR — but it's
# a far easier one to reach for. SCREEN_TEXT=false removes it entirely.
#SCREEN_TEXT=true
#SCREEN_TEXT_MAX_CHARS=4000
# ── Quiet hours / do-not-disturb (optional) ────────────────────────────────
# Comma-separated HH:MM-HH:MM ranges; wrapping past midnight is fine. While
# napping the pet dims, stops wandering and makes no proactive noise — the
# wake word and click-to-talk still work.
#QUIET_HOURS=23:00-08:00
#DND_ON_FULLSCREEN=true
# ── Desktop notification bridge (optional, Linux/D-Bus) ────────────────────
# Forwards matching desktop notifications to the server so Bolt can react to
# them. Off by default: each forwarded notification is a converse() round
# trip. NOTIFICATION_FILTER is a regex over "<app>: <summary> <body>".
#NOTIFICATION_BRIDGE=false
#NOTIFICATION_FILTER=build|deploy|calendar
#NOTIFICATION_MIN_INTERVAL_SECONDS=60
# Notifications queue while the pet is napping (the heartbeat that forwards them
# doesn't run). These two stop an overnight backlog becoming a monologue at 8am:
# the queue drops its oldest past the limit, and anything staler than the age
# limit is discarded rather than read out.
#NOTIFICATION_QUEUE_LIMIT=20
#NOTIFICATION_MAX_AGE_SECONDS=900
# ── Push-to-talk (optional) ─────────────────────────────────────────────────
# Global hotkey; needs pynput and a session that allows global key hooks
# (most Wayland sessions don't). Leave blank to disable.
#PUSH_TO_TALK_HOTKEY=ctrl+alt+space
# ── Wake-word tuning (optional) ─────────────────────────────────────────────
# Scores within this margin below the threshold show up as "near misses" in
# the tray's wake-word tuner.
#WAKE_NEAR_MISS_MARGIN=0.2
#WAKE_NEAR_MISS_LIMIT=40
# ── sudo password prompts (optional) ────────────────────────────────────────
# The pet has no terminal, so a server-relayed `sudo` would block forever on
# a tty nobody is watching. With this on, bare `sudo` becomes `sudo -A` and
# the password is collected in a desktop dialog you have to answer — a real
# askpass binary if one is installed, otherwise a generated zenity/kdialog
# wrapper in ~/.cache/bolt-pet/askpass.sh.
# Set it to false if you'd rather Bolt never be able to ask for root: sudo
# commands then just fail. Read the dialogs — that box is the only thing
# between "Bolt decided to run sudo" and it running.
#SUDO_ASKPASS_PROMPT=true
#SUDO_ASKPASS_HELPER= # blank = auto-detect
#SUDO_COMMAND_TIMEOUT_SECONDS=180 # long enough for a human to answer
# ── File delivery (optional) ────────────────────────────────────────────────
# The server's deliver_files tool ("send me that report") queues workspace
# files on this session; the pet fetches and saves them automatically.
#RECEIVE_FILES=true
#DELIVERED_FILES_DIR=~/Downloads/Bolt
# ── Misc (optional) ──────────────────────────────────────────────────────────
#COMMAND_TIMEOUT_SECONDS=30
#HEARTBEAT_INTERVAL_SECONDS=60
#HISTORY_LIMIT=100