Commit Graph

123 Commits

Author SHA1 Message Date
javis-bot
7da2fcb5e5 feat(stt): beam-search decoding + no prev-text conditioning for accuracy
Whisper was decoding with beam_size=1 (greedy), the least accurate setting,
which hurt recognition on short/accented/noisy Discord-mic speech. Switch the
default to beam search (5, Whisper's own default) and stop conditioning on the
previous clip's transcript (which causes repetition/drift on isolated short
utterances rather than helping). Both are env-tunable (STT_BEAM_SIZE,
STT_CONDITION_ON_PREV) so accuracy/latency can be traded without a code change;
wired into docker-compose and documented in .env.example.
2026-06-24 17:55:20 +09:00
javis-bot
680f5a656a docs: reflect the separate auxiliary intent/router model in llm_contexts + README
Some checks failed
Release / semantic-release (push) Successful in 18s
tests / Unit tests (Linux, Python 3.11) (push) Failing after 5m18s
Release / build-linux (push) Failing after 7m6s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
Follow-up to the OLLAMA_INTENT_MODEL split: document that the Docker stack runs
intent judging / tool routing / extraction on a small qwen2.5:3b (pulled by
ollama-init) kept separate from the big chat answer model, and that setting
OLLAMA_INTENT_MODEL = OLLAMA_CHAT_MODEL folds them back onto one resident model.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-23 17:38:58 +09:00
javis-bot
b52ffd2b18 perf: run auxiliary LLM calls on a small model, big model only for the answer
Some checks failed
Release / semantic-release (push) Successful in 19s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / build-linux (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
tests / Unit tests (Linux, Python 3.11) (push) Has been cancelled
Intent judging, tool routing and arg extraction are classification/JSON calls,
not the spoken answer, yet the stack aliased OLLAMA_INTENT_MODEL back to the big
chat model — so each command paid the big model's cost 2-3 times for routing
before the reply even ran. With the GPU on, that round-trip stacking is the main
remaining per-turn latency. Default OLLAMA_INTENT_MODEL to qwen2.5:3b (the
project's reference small model, clean Korean on classification) and have
ollama-init pull it. The reply engine already routes these calls through
intent_judge_model, so answer quality is untouched; set OLLAMA_INTENT_MODEL =
OLLAMA_CHAT_MODEL to fold back onto one resident model.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.8.1
2026-06-23 17:35:40 +09:00
javis-bot
140fc56f18 feat: play the Nth YouTube result in browseAndPlay via an index arg
Some checks failed
Release / semantic-release (push) Successful in 22s
tests / Unit tests (Linux, Python 3.11) (push) Failing after 5m16s
Release / build-linux (push) Failing after 7m10s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
agents/llm.md promises "play the Nth video from the top", but browseAndPlay
only ever clicked the first result. Add an optional 1-based index argument
(default 1, backward-compatible) threaded to the Node helper, which now clicks
the Nth a#video-title and clamps to the number of results returned so asking
beyond the list plays the last available video instead of failing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.8.0
2026-06-23 15:33:45 +09:00
javis-bot
5ee47827f3 perf: cap chat output tokens via ollama_num_predict to bound reply latency
Spoken (TTS) replies are 1-2 sentences, so an unbounded num_predict only
exposes the worst case where the chat model rambles or loops. Add an
ollama_num_predict config (default 512, 0 disables) wired into the reply
loop's chat call on both the native- and text-tool paths. The 512-token
headroom stays well above this app's short tool-call JSON, so capping never
truncates a tool call. This keeps the user's quality model instead of
downgrading it. Configurable in the container via OLLAMA_NUM_PREDICT.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-23 15:33:45 +09:00
javis-bot
c189ce2e65 feat: Korean Chrome locale, agents/llm.md voice instructions, drop emoji rule
Some checks failed
Release / semantic-release (push) Successful in 26s
tests / Unit tests (Linux, Python 3.11) (push) Failing after 5m17s
Release / build-linux (push) Failing after 7m7s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
- run-chrome.sh: render web content (YouTube/Google/Naver) in Korean. --lang
  only sets Chrome's UI; the Accept-Language sent to sites comes from the
  profile's intl.accept_languages, which a persisted user-data-dir kept at
  en-US. Seed the profile to ko-KR and add --accept-lang=ko-KR,ko.
- agents/llm.md: runtime instructions for the reply LLM (loaded by the agents
  feature) — name "자비스", concise 1-2 sentence TTS replies (no emojis/markdown),
  nuance-based intent, and YouTube voice controls (open/search/play Nth/pause/
  back) via the on-screen browser tool.
- CLAUDE.md: drop the "use emojis in CLI output" rule — this assistant replies by
  Discord voice, not CLI, so output should be plain.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.7.0
2026-06-23 04:34:17 +09:00
javis-bot
086dd5cde7 fix: accept edge as a valid tts_engine and migrate stale persisted engines
Some checks failed
Release / semantic-release (push) Successful in 34s
tests / Unit tests (Linux, Python 3.11) (push) Failing after 5m17s
Release / build-linux (push) Failing after 7m9s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
load_settings() coerced any tts_engine outside {piper, chatterbox} to piper, so
with TTS_ENGINE=edge the reply engine saw "piper" and treated the voice as
English-only in reply_language_directive() (only the OUTPUT_LANGUAGE lock kept
replies Korean). Add "edge" (and "melo") to the accepted set so the engine is
labelled multilingual correctly.

Also: a stale tts_engine in the persistent /data/jarvis-settings.json (melo/xtts
from an earlier voice, no longer built) would override the configured engine via
the entrypoint merge and leave the bot silent. Reset those to the env engine
during the merge.

Verified: load_settings() with tts_engine=edge now returns "edge"; the merge
maps melo/xtts -> edge; reply_language_directive("edge") is multilingual; 27
tests pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.6.1
2026-06-23 03:49:53 +09:00
javis-bot
f64d76e737 feat: use Edge TTS (Korean Hyunsu voice @ +45%) as the default voice
Some checks failed
Release / semantic-release (push) Successful in 31s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / build-linux (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
tests / Unit tests (Linux, Python 3.11) (push) Has been cancelled
The user chose Microsoft Edge TTS, voice ko-KR-HyunsuMultilingualNeural at rate
+45% (~1.45x), as the natural Korean voice. Wire it into the bridge and make it
the default engine.

- bridge/server.py: _edge_synthesize() calls edge-tts and transcodes the MP3 to
  PCM16 mono WAV with the system ffmpeg (temp file for a correct header);
  TTS_ENGINE default -> edge; EDGE_TTS_VOICE / EDGE_TTS_RATE env-driven
- requirements-bridge.txt: add edge-tts (lightweight; httpx)
- compose/.env.example/README: TTS_ENGINE=edge + EDGE_TTS_* knobs; note the
  online/privacy trade-off (reply text is sent to Microsoft, needs internet)
- drop the now-unused MeloTTS build layer (Dockerfile) and melo-worker
  (supervisord) — edge synthesises in-process, no model/worker baked, slimmer
  and faster image; settings UI engine list -> edge/piper, restart only bridge

Verified on host: edge-tts -> ffmpeg yields a valid 16-bit mono 24kHz WAV;
envsubst renders tts_engine=edge; docker build --check + 26 tests pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.6.0
2026-06-23 03:44:15 +09:00
javis-bot
11c3621093 fix: make container TTS engine env-driven so melo isn't overridden by piper
Some checks failed
Release / semantic-release (push) Successful in 30s
tests / Unit tests (Linux, Python 3.11) (push) Failing after 5m17s
Release / build-linux (push) Failing after 7m3s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
docker/jarvis-config.template.json hardcoded "tts_engine": "piper". entrypoint
renders it into /app/config/jarvis.json, and bridge _tts_engine_setting() reads
that JSON BEFORE the env — so TTS_ENGINE=melo in .env was ignored and the bot
synthesised Korean with the English Piper voice (the "foreign accent" the user
heard); the warm melo-worker sat unused.

Template now carries ${TTS_ENGINE}; compose sets TTS_ENGINE=${TTS_ENGINE:-melo}
so envsubst renders the real engine. Verified: envsubst with TTS_ENGINE=melo
yields "tts_engine": "melo", and `docker compose config` passes TTS_ENGINE=melo.
Added a regression test that the template stays env-driven and renders the
configured engine.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.5.2
2026-06-23 03:27:33 +09:00
javis-bot
7ad5d99380 Revert "feat: replace MeloTTS with Coqui XTTS-v2 natural Korean voice"
Some checks failed
Release / semantic-release (push) Successful in 35s
tests / Unit tests (Linux, Python 3.11) (push) Failing after 5m16s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
Release / build-linux (push) Has been cancelled
This reverts commit 39a0944105.
v1.5.1
2026-06-23 03:15:54 +09:00
javis-bot
39a0944105 feat: replace MeloTTS with Coqui XTTS-v2 natural Korean voice
Some checks failed
Release / semantic-release (push) Successful in 30s
tests / Unit tests (Linux, Python 3.11) (push) Failing after 5m17s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
Release / build-linux (push) Has been cancelled
MeloTTS's single Korean speaker sounded non-native ("foreign accent"). Swap it
for Coqui XTTS-v2 with the built-in female studio speaker "Ana Florence"
(language ko), the natural voice used in earlier local runs.

- bridge/xtts_worker.py: new warm HTTP worker (own /opt/xtts venv), same
  /synth + /health contract and PCM16 output as the old melo worker
- docker/setup-xtts.sh: builds the venv with cu128 torch (Blackwell) + Coqui
  TTS and bakes the XTTS-v2 model offline. Pins transformers>=4.57,<5 (5.x
  removed isin_mps_friendly, breaking XTTS) and installs the [codec] extra
  (torch>=2.9 needs torchcodec) — both verified by a real host synth
- Dockerfile: replace the melo build layer with the xtts layer
- supervisord.conf: melo-worker -> xtts-worker, env passthrough for
  XTTS_DEVICE/SPEAKER/LANGUAGE (always set via compose defaults)
- bridge/server.py: default TTS_ENGINE=xtts, route to the xtts worker, generic
  worker-synth helper, neural-only fallback flag (XTTS_FALLBACK_PIPER)
- settings UI: engine dropdown xtts/piper, drop the dead melo_speed field, fix
  the supervisorctl restart target to xtts-worker
- compose/.env.example/README: XTTS_* vars, speaker/language knobs, remove melo
- remove bridge/melo_worker.py and docker/setup-melo.sh
- tests: xtts treated as multilingual (not English-only)

Verified on host: coqui-tts loads XTTS-v2 and synthesises Korean as
"Ana Florence" to a 16-bit mono 24kHz WAV.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.5.0
2026-06-23 03:08:01 +09:00
javis-bot
b9f637faa4 fix: stop hardcoding MELO_SPEED so the .env override reaches the worker
Some checks failed
Release / semantic-release (push) Successful in 26s
tests / Unit tests (Linux, Python 3.11) (push) Failing after 5m13s
Release / build-linux (push) Failing after 7m8s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
supervisord.conf passed MELO_DEVICE through as %(ENV_MELO_DEVICE)s but pinned
MELO_SPEED="1.5", so lowering MELO_SPEED in .env had no effect — the worker
always got 1.5. Pass MELO_SPEED through with %(ENV_MELO_SPEED)s and set a
compose default (MELO_SPEED=${MELO_SPEED:-1.5}, same pattern as MELO_DEVICE) so
the supervisord expansion always resolves and an .env value actually changes
the speaking rate. Default rate is unchanged (1.5). melo_worker logs the
resolved speed at startup, so the env->worker path is verifiable.

Verified: _resolve_speed() returns 1.1 for MELO_SPEED=1.1 (1.5 otherwise), and
`MELO_SPEED=1.1 docker compose config` renders MELO_SPEED: "1.1" into the env.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.4.1
2026-06-23 01:02:43 +09:00
javis-bot
2f000ac6c8 feat: load operator instructions from agents/*.md into the reply prompt
Some checks failed
Release / semantic-release (push) Successful in 30s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / build-linux (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
tests / Unit tests (Linux, Python 3.11) (push) Has been cancelled
Drop Markdown files into an agents/ folder and their contents are appended to
the main reply LLM's system prompt, so an operator can extend the assistant's
rules/tone without code changes. Files are concatenated in filename order
(use 00-, 10- prefixes to control ordering) and re-read once per turn, so edits
apply on the next reply with no rebuild/restart. Fail-open: a missing, empty,
or unreadable folder yields no instructions and never breaks a reply.

- load_agent_instructions() in system_prompt.py (AGENTS_DIR env, default
  /app/agents); reads *.md only, skips blanks, ignores non-dir paths
- engine.py appends it alongside the existing settings-UI llm_instructions,
  under the same "Additional instructions from the operator:" framing
- docker-compose.yml bind-mounts ./agents:/app/agents:ro and sets AGENTS_DIR
- agents/example.md.sample starter template (.sample is not loaded)
- tests cover ordering, md-only filtering, blank-skip, env/arg resolution,
  and fail-open paths
- README, .env.example, docs/llm_contexts.md updated

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.4.0
2026-06-23 00:57:54 +09:00
javis-bot
677bfcd2a9 feat: log the resolved whisper device on bridge load
Some checks failed
Release / semantic-release (push) Successful in 24s
tests / Unit tests (Linux, Python 3.11) (push) Failing after 5m19s
Release / build-linux (push) Failing after 7m10s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
The bridge only logged Whisper's device on the CPU-fallback path, so a
successful GPU (or silent CPU) load was invisible. Print the CTranslate2-
resolved device on success and on the fallback load, so it is verifiable that
STT is actually running on cuda alongside ollama (GPU) and MeloTTS (cuda).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.3.0
2026-06-23 00:19:20 +09:00
javis-bot
e49be6d04e fix: add video driver capability so NVENC works in the container
Some checks failed
Release / semantic-release (push) Successful in 31s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / build-linux (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
tests / Unit tests (Linux, Python 3.11) (push) Has been cancelled
The Go-Live broadcast encodes with h264_nvenc, but the image only requested
NVIDIA_DRIVER_CAPABILITIES=compute,utility. The NVIDIA Container Toolkit gates
which driver libraries it injects by capability, and the NVENC/NVDEC libs
(libnvidia-encode.so.1 / libnvidia-decode.so.1) come with the `video`
capability. Without it the broadcast ffmpeg dies with
"Cannot load libnvidia-encode.so.1", the capture produces no packets, and
Go-Live never connects, while CUDA workloads (ollama/whisper/melo) and
nvidia-smi keep working because compute+utility are present.

Add `video` so hardware encode is available. Applies to both Linux (CDI) and
Windows Docker Desktop (WSL2).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.2.3
2026-06-23 00:16:12 +09:00
javis-bot
1efabe03b1 fix: strip CR from container shell scripts in Dockerfile build
Some checks failed
Release / semantic-release (push) Successful in 26s
tests / Unit tests (Linux, Python 3.11) (push) Failing after 5m12s
Release / build-linux (push) Failing after 7m8s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
.gitattributes pins *.sh to LF, but that only helps after a full working-tree
renormalise, which a Windows build box may not have done. The image build kept
failing at `RUN bash setup-melo.sh` because the checked-out file still had CRLF,
so bash read line 18 as `set -euxo pipefail\r` and aborted with
"set: pipefail: invalid option name".

Strip CR from setup-melo.sh before running it, and normalise all docker/scripts
shell scripts to LF after the app COPY so their shebangs (entrypoint, run-*.sh)
also survive a CRLF checkout. Makes the build EOL-agnostic regardless of host
autocrlf settings.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.2.2
2026-06-22 23:35:12 +09:00
javis-bot
09cd4c5e31 fix: pin docker shell scripts to LF to stop CRLF breaking the image build
Some checks failed
Release / semantic-release (push) Successful in 24s
tests / Unit tests (Linux, Python 3.11) (push) Failing after 5m18s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
Release / build-linux (push) Has been cancelled
Windows checkouts with autocrlf=true inject CR into docker/*.sh, so inside
the Linux container `set -euxo pipefail` is read as `pipefail\r` and bash
aborts with "set: pipefail: invalid option name", failing setup-melo.sh and
the whole image build. .gitattributes already pinned .bat/.cmd/.ps1 to CRLF
but never pinned .sh, leaving all nine container scripts exposed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.2.1
2026-06-22 23:27:46 +09:00
javis-bot
00ce813845 docs: warn that COMPOSE_FILE uses ';' on Windows, ':' on Linux/macOS
Some checks failed
Release / semantic-release (push) Successful in 26s
tests / Unit tests (Linux, Python 3.11) (push) Failing after 5m21s
Release / build-linux (push) Failing after 7m6s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
Windows users following the docs hit "The system cannot find the file
specified" because COMPOSE_FILE's separator is OS-specific (':' collides
with the C: drive letter). Fix every Windows example to use ';', add an
explicit OS-separator warning in .env.example, README, DEPLOY.md and the
gpu-windows compose comment, and point users at the explicit `-f` form as
a separator-agnostic alternative.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-22 23:13:33 +09:00
javis-bot
c56ce1eb30 feat: human-like typing for browser Google and YouTube search
Some checks failed
Release / semantic-release (push) Successful in 26s
tests / Unit tests (Linux, Python 3.11) (push) Failing after 5m16s
Release / build-linux (push) Failing after 7m11s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
Make the browser search helper search the way a person does: load the
site home page, type the query into the search box one key at a time, and
press Enter — for both Google `search` and `youtube` — instead of jumping
straight to a results URL. Supports the goal of a human-like assistant.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.2.0
2026-06-22 21:09:15 +09:00
javis-bot
597207dd33 feat: reuse a signed-in Chrome profile for browser web search
Add CHROME_USER_DATA_DIR so the browser search fallback can open Chrome
against a dedicated, Google-signed-in profile instead of a fresh anonymous
session. A returning signed-in profile is what actually avoids Google's
/sorry bot-detection page, so this is the reliable way to get browser
Google search in plain text turns. Fallback order is now CDP (broadcast
Chrome) -> persistent profile (when configured) -> ephemeral headless,
all still fail-open to the DDG/Brave/Wikipedia cascade.

Document the profile in .env.example and web_search.spec.md.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-22 20:57:25 +09:00
javis-bot
98a1825d01 feat: headless Chrome fallback for browser web search outside broadcast
browse-search.mjs only connected to the on-screen broadcast Chrome over
CDP, so browser-based Google search worked only during a live broadcast;
plain text turns fell through to the DDG cascade. Add a headless fallback
(system Chrome via channel:'chrome', else Playwright's bundled chromium)
for `search` mode so general conversation can use Google at no API cost.
`youtube` still requires the visible broadcast Chrome.

Detect Google's /sorry bot-detection interstitial structurally by URL and
fail fast so the caller fail-opens to DDG/Brave/Wikipedia instead of
treating the challenge page as empty results.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-22 20:52:54 +09:00
javis-bot
da27c5a306 docs: warn that personal Google login is blocked on the Gemini CLI path
Google now rejects personal Google accounts on the Gemini CLI OAuth login
("This client is no longer supported for Gemini Code Assist for individuals").
The setup docs previously sent every user down "Sign in with Google" with no
warning. Note the block, recommend GEMINI_AUTH=apikey for personal accounts,
and clarify that real-time search fail-opens to DDG/Brave/Wikipedia regardless.

Docs only; no runtime default change.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-22 19:44:12 +09:00
javis-bot
5b6a67963a feat: make GEMINI_AUTH=oauth authenticate in Docker
Some checks failed
Release / semantic-release (push) Successful in 25s
tests / Unit tests (Linux, Python 3.11) (push) Failing after 5m17s
Release / build-linux (push) Failing after 7m8s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
OAuth cannot be done interactively in the headless container, so the login
must be seeded into the mounted ~/.gemini. Three problems are fixed:

- Mount fragility on the Windows Docker Desktop target: the creds mount
  defaulted to ${HOME}/.config/javis/gemini, but ${HOME} is often unset when
  compose runs outside a WSL shell, silently mounting the wrong dir. Default is
  now the project-local ./docker/gemini-oauth (cross-platform), GEMINI_OAUTH_DIR
  still overrides.
- No visibility: when oauth is selected but no login is seeded, the path
  silently degraded to DDG/Brave. Added gemini_oauth_ready() + a one-time debug
  hint and a startup entrypoint warning (skipped on the browser role, fail-open).
- Seeding guidance: oauth_creds.json is the essential credential (refresh token;
  GOOGLE_GENAI_USE_GCA=true forces OAuth), which is what the readiness check and
  warning verify; docs recommend copying the whole ~/.gemini for convenience.

Adds docker/gemini-oauth/ seed dir (.gitkeep) with the login files gitignored,
GEMINI_OAUTH_DIR in .env.example, and updates DEPLOY.md, stream_browser_modes.md
and llm_contexts.md. Covered by 3 new tests (10 passed total).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.1.0
2026-06-22 18:05:22 +09:00
javis-bot
53be1567b1 docs: README — OS-specific install/run (Linux CDI vs Windows Docker Desktop)
Some checks failed
Release / semantic-release (push) Successful in 32s
tests / Unit tests (Linux, Python 3.11) (push) Failing after 8m20s
Release / build-linux (push) Failing after 7m11s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
Document that the base compose has no GPU and the GPU is enabled via an
OS-specific override (docker-compose.gpu-linux.yml CDI vs
docker-compose.gpu-windows.yml deploy-reservations), with per-OS host prep,
COMPOSE_FILE shortcut, CPU-only fallback, and Windows manual-run differences
(venv activation, ffmpeg, no .sh scripts / WSL2). Fix stale lines (GPU moved
out of base compose; default model qwen2.5:3b) and add MELO_DEVICE /
output_language to the env list.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-18 04:37:40 +09:00
javis-bot
ccddbd6448 test: settings output_language survives save→apply→recreate
Some checks failed
Release / semantic-release (push) Successful in 42s
Release / build-windows (push) Has been cancelled
Release / build-macos (arm64, macos-latest) (push) Has been cancelled
Release / build-macos (x64, macos-15-intel) (push) Has been cancelled
Release / build-linux (push) Has been cancelled
Release / release-main (push) Has been cancelled
Release / release-develop (push) Has been cancelled
tests / Unit tests (Linux, Python 3.11) (push) Has been cancelled
Integration test driving the real bridge _save() and engine
_resolve_output_language(): a language chosen in the settings UI is written to
both the persistent volume and the runtime config, applies immediately (config
wins over the OUTPUT_LANGUAGE env), and survives a simulated container recreate
(entrypoint re-renders the config then merges the persistent override). Also
asserts the persona and reply directive both follow the persisted language.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.0.0
2026-06-16 19:56:13 +09:00
javis-bot
7870a76314 fix: persona uses settings output_language, matching the reply directive
The persona prompt was built from the raw OUTPUT_LANGUAGE env while the
reply-language directive read the settings-web UI value (config JSON), so
changing the language in the settings page was honoured by the directive
but ignored by the persona, leaving them contradicting each other.

Add _resolve_output_language() as the single source of truth (config wins
over env) and feed the same resolved value to both build_system_prompt()
and reply_language_directive(). Update docs/llm_contexts.md to match.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-16 19:47:26 +09:00
javis-bot
b3088dd75f fix: settings output_language overrides the compose env default
The settings-UI output_language was ignored because the OUTPUT_LANGUAGE env took
precedence. Read the config value first, fall back to env, so changing the
language in /settings actually applies.
2026-06-15 16:57:01 +09:00
javis-bot
8868381f13 fix: minimal Chrome flags (drop --test-type/AutomationControlled) + policy infobar suppress
Per the flag hypothesis: remove the automation-signaling flags that can trigger
Google's /sorry/ challenge. Suppress the --no-sandbox warning bar with a Chrome
managed policy (CommandLineFlagSecurityWarningsEnabled=false) instead of
--test-type, so the infobar stays hidden without the automation signal.
2026-06-15 16:51:11 +09:00
javis-bot
247edda3eb fix: google anti-bot flag + persistent/safe settings apply + TTS engine wiring
- Chrome: --disable-blink-features=AutomationControlled (+ ko-KR) so Google
  shows results, not the /sorry/ automation block.
- Settings persist to /data/jarvis-settings.json (survives recreate; entrypoint
  re-merges it) AND the runtime config; apply restarts via a DETACHED process so
  the HTTP response isn't dropped when the bridge restarts.
- Bridge reads tts_engine from the settings config so the TTS-engine choice
  actually applies.
2026-06-15 13:13:11 +09:00
javis-bot
84e435f916 feat: settings web UI (models / STT / TTS speed / language / LLM instructions)
Adds /settings (served by the bridge) to change the LLM model (from installed
Ollama models), Whisper model, TTS engine + MeloTTS speed, output language,
agentic max-turns, thinking mode, and free-form LLM instructions — live, with a
'apply' that restarts the bridge + TTS worker. Settings persist to the runtime
config JSON; engine reads output_language + llm_instructions and the TTS worker
reads melo_speed from it. Bridge port publishable for access.
2026-06-15 13:05:46 +09:00
javis-bot
3bdc7d078a feat: cross-platform compose (Ubuntu CDI + Windows Docker Desktop GPU)
Base compose is GPU-agnostic; GPU is added by a per-OS override selected via
COMPOSE_FILE in .env (docker-compose.gpu-linux.yml for Ubuntu/CDI,
docker-compose.gpu-windows.yml for Windows 11 Docker Desktop). Adds .env.example
split-deployment section + docs/DEPLOY.md covering all-in-one and browser+bot
layouts on both OSes.
2026-06-15 13:00:04 +09:00
javis-bot
8dd6386af8 fix: search like a person — open homepage, type in the site's search box
controlBrowser search opened the results URL directly (search.naver.com?query).
Now it navigates to the homepage (www.naver.com / google.com), clicks the
on-page search box, types the query char-by-char and presses Enter — real
human-style search, visible on screen.
2026-06-15 12:42:58 +09:00
javis-bot
aebf183950 feat: browser-control server on host (real input) + remote-bot routing + ignore env backups
- control-server.mjs runs chrome-control.mjs LOCALLY on the browser host, so a
  remote bot's controlBrowser (BROWSER_CONTROL_URL) drives real xdotool input
  on THIS screen instead of the bot machine. Published on the LAN.
- controlBrowser tool posts to BROWSER_CONTROL_URL when set, else runs locally.
- Drop hard depends_on ollama so a browser-host doesn't start Ollama.
- gitignore .env.bak*/*.bak (a backup with tokens had been left untracked).
2026-06-15 10:41:57 +09:00
javis-bot
1935c1a6bc feat: split-deployment roles (browser-host on LAN + remote bot)
Add JARVIS_ROLE (full|browser|bot) via a run-if-role.sh supervisord guard so
one image serves three layouts. Make Chrome CDP bind configurable (CDP_BIND)
and publishable on the LAN (CDP_PUBLISH_BIND) so a bot on another PC can drive
this host's on-screen Chrome over the internal network (no auth, as requested).
2026-06-15 10:23:55 +09:00
javis-bot
bdb012fc7c fix: weather passes named city from utterance; clean navigate reply
GeoIP auto-detect is unavailable in the container, so '부산 날씨' failed
(no location). Extract the city from the utterance and pass it to getWeather.
Also report navigate by site name instead of the mid-load about:blank url.
2026-06-15 01:02:35 +09:00
javis-bot
49061d30f0 fix: deterministic browser navigate for 'go back to <site>' (구글로 돌아가)
The 7B narrated '구글 메인으로 돌아갑니다' without acting, so the screen stayed on
Naver. Split site intent into SEARCH vs NAV: nav words (돌아가/이동/열어/메인/go
back) now drive controlBrowser.navigate to the site homepage directly, search
words run controlBrowser.search — both deterministically, no LLM.
2026-06-15 00:58:53 +09:00
javis-bot
c522e1b285 fix: deterministic weather → one clean Korean sentence (no 'Celsius')
getWeather now returns only the Korean sentence (지금 <곳> 날씨는 <상태>, 기온 N도
(체감 M도)입니다) with no English/°C source. A deterministic weather path in the
engine returns it verbatim, bypassing the 7B which was rephrasing into multiple
sentences and leaking 'Celsius'.
2026-06-14 22:46:03 +09:00
javis-bot
54c3ce7d1b feat: show speaker nickname instead of raw user ID in voice logs
Resolve the Discord user ID to a server nickname / global name (cached) and
display that in the transcript channel + console logs.
2026-06-14 22:39:06 +09:00
javis-bot
d970bf276e fix: harden Korean-only output lock (front+end, explicit script ban)
qwen2.5:7b leaked Chinese/Cyrillic mid-reply despite the OUTPUT_LANGUAGE
lock, which was buried mid-prompt. Repeat the lock at the END of the system
prompt (recency) and ban specific foreign scripts explicitly.
2026-06-14 22:25:33 +09:00
javis-bot
3d620dc4c7 fix: concise Korean weather reply (current conditions, one sentence)
getWeather returned a verbose multi-section English forecast that the 3B
re-synthesised into long, CJK/°F-leaking answers. Hand it a ready-to-speak
Korean one-liner (지금 <곳> 날씨는 <상태>, 기온 N도(체감 M도)입니다) and drop the
hourly/7-day firehose from the default voice reply.
2026-06-14 21:49:53 +09:00
javis-bot
09afc21283 feat: split recording vs STT-processing time in turn logs
Log the captured speech-clip duration (녹음/음성) separately from the Whisper
transcription time (STT처리) so it's clear whether a slow turn is the
listening/recording or the transcription, per the user's request.
2026-06-14 21:45:50 +09:00
javis-bot
11a72cb296 fix: deterministic on-screen site search + lock replies to Korean
- Site-specified search ("네이버에서 X 검색해줘") now runs controlBrowser.search
  directly in the engine when broadcasting, instead of relying on the 3B model
  to emit the tool call (it kept narrating "검색하겠습니다" without acting).
- Set OUTPUT_LANGUAGE=ko so replies are Korean-only — stops the small model
  leaking CJK/Hanja and English fragments (每, 朗, "feels like") into weather
  and other answers, and keeps them concise.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-14 21:07:26 +09:00
javis-bot
37759f2b2c perf: conversational fast-path (skip enrichment) + shorter silence wait
Greetings/small-talk routed no data tool yet still ran the episodic memory
enrichment (LLM keyword extract + diary/graph search, ~1s) every turn. Skip it
when the router picked no external-data tool — the always-injected warm profile
still personalises the reply. Also drop the voice silence-detection wait
800ms -> 600ms for snappier turn-taking. Warm "안녕" now lands well under the
3-4s target.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-14 03:21:52 +09:00
javis-bot
4bc7f836ae fix: native tool-calling for qwen2.5 (tools actually fire) + kill Chrome infobars
Root cause of "weather/search do nothing": the engine forced TEXT tool-calling
for all <=7B models, but qwen2.5:3b emits clean NATIVE tool calls and fails at
the text format — so it just narrated ("부산 날씨는 맑습니다") and never called
getWeather/webSearch/controlBrowser. Use native tool-calling for tool-capable
small families (qwen2.5/qwen3/llama3.x/mistral); native still auto-falls back
to text on HTTP 400, so non-tool models (gemma) are unaffected.

Also launch Chrome with --test-type (removes the "--no-sandbox unsupported
flag" infobar) and disable the Translate feature/popup.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-14 03:08:49 +09:00
javis-bot
642fa42561 fix: drop webSearch when a site is named in screen-share, forcing controlBrowser
The 3B model kept choosing webSearch over controlBrowser even when offered, so
'네이버에서 X 검색' still used the invisible web path. When broadcasting and the
user explicitly names a site, remove webSearch from the allow-list so the
on-screen browser is the only search route.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-14 02:57:51 +09:00
javis-bot
f3d34bab4d fix: always offer controlBrowser in screen-share so on-screen search works
The small router reflexively routed every "search/open" intent to webSearch
and never surfaced controlBrowser, so "네이버에서 X 검색해줘" did nothing on the
broadcast. Union controlBrowser (+browseAndPlay) into the allow-list every
turn in screen-share mode (like setBroadcast), and steer the model in the
system prompt to prefer the on-screen browser over webSearch when available.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-14 02:55:33 +09:00
javis-bot
c21c5b225f feat: controlBrowser 'search' action + one-sentence voice replies
- Add a one-shot `search` action (site=naver/google/daum/youtube/bing) that
  navigates the on-screen browser straight to the results page, so a small
  model can satisfy "search X on Naver" in a single tool call instead of a
  fragile navigate->type->enter chain.
- Sharpen the tool description to steer the router to controlBrowser (not
  webSearch) for anything that should happen IN the visible browser.
- System prompt: answer in one short sentence (voice assistant) — also cuts
  TTS time.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-14 02:52:47 +09:00
javis-bot
109dbc7e16 feat: robust controlBrowser — real xdotool input, tabs/back/forward/popups
- Install xdotool + wmctrl (late Docker layer, preserves the melo cache) so
  the on-screen Chrome gets real X input (visible cursor, char-by-char typing)
  instead of synthetic events; falls back to the Playwright API if absent.
- Fix active-tab detection (probe document.visibilityState instead of assuming
  tab 0) so sequential ops target the right tab.
- Add back / forward / refresh; new/switch/close tabs via real keyboard
  (Ctrl+T / Ctrl+<n> / Ctrl+W) when xdotool is present.
- Auto-dismiss native JS dialogs; closePopups clears blank/popup tabs.
- Report broadcast (Go-Live) state in status from the turn context.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-14 02:33:59 +09:00
javis-bot
b18217fcdd fix: let melo-worker honour MELO_DEVICE from env (was hardcoded cpu)
supervisord hardcoded MELO_DEVICE=cpu, overriding the compose MELO_DEVICE=cuda
so MeloTTS stayed on CPU even after the GPU torch swap. Interpolate the
container env instead.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-14 02:26:24 +09:00
javis-bot
3d1e56f60f feat: controlBrowser tool — human-operable on-screen Chrome
Adds a general browser-control tool (navigate to any site, list/open/close/
switch tabs, close popups, click, type, scroll, screenshot) for the Go-Live
Chrome, on top of the existing CDP + xdotool human-input layer (visible
cursor, char-by-char typing). Closes the gap where "open Naver" had no tool
and the model confabulated success. Also adds a system-prompt rule against
claiming actions no tool actually performed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-14 02:22:36 +09:00