v0.3.0#335
Conversation
… 'friend-backend' to 'chronicle-backend' across various files, including setup instructions, Docker configurations, and service logs.
Update documentation and configuration to reflect the transition from… - Bypassing rule as its required upstream
* refactor memory * add config * docstring * more cleanup * code quality * code quality * unused return * DOTTED GET * Refactor Docker and CI configurations - Removed the creation of `memory_config.yaml` from the CI workflow to streamline the process. - Updated Docker Compose files to mount `config.yml` for model registry and memory settings in both services. - Added new dependencies for Google API clients in `uv.lock` to support upcoming features. * Update configuration files for model providers and Docker setup - Changed LLM, embedding, and STT providers in `config.yml` to OpenAI and Deepgram. - Removed read-only flag from `config.yml` in Docker Compose files to allow UI configuration saving. - Updated memory configuration endpoint to accept plain text for YAML input. * Update transcription job handling to format speaker IDs - Changed variable name from `speaker_name` to `speaker_id` for clarity. - Added logic to convert integer speaker IDs from Deepgram to string format for consistent speaker labeling. * Remove loading of backend .env file in test environment setup - Eliminated the code that loads the .env file from the backends/advanced directory, simplifying the environment configuration for tests. * Enhance configuration management and setup wizard - Updated README to reflect the new setup wizard process. - Added functionality to load and save `config.yml` in the setup wizard, including default configurations for LLM and memory providers. - Improved user feedback during configuration updates, including success messages for configuration file updates. - Enabled backup of existing `config.yml` before saving changes. * Enhance HTTPS configuration in setup wizard - Added functionality to check for existing SERVER_IP in the environment file and prompt the user to reuse or enter a new IP for SSL certificates. - Improved user prompts for server IP/domain input during HTTPS setup. - Updated default behavior to use existing IP or localhost based on user input. - Changed RECORD_ONLY_ENROLLED_SPEAKERS setting in the .env template to false for broader access. * Add source parameter to audio file writing in websocket controller - Included a new `source` parameter with the value "websocket" in the `_process_batch_audio_complete` function to enhance audio file context tracking. --------- Co-authored-by: 0xrushi <6279035+0xrushi@users.noreply.github.com>
* refactor memory * add config * docstring * more cleanup * code quality * code quality * unused return * DOTTED GET * Refactor Docker and CI configurations - Removed the creation of `memory_config.yaml` from the CI workflow to streamline the process. - Updated Docker Compose files to mount `config.yml` for model registry and memory settings in both services. - Added new dependencies for Google API clients in `uv.lock` to support upcoming features. * Update configuration files for model providers and Docker setup - Changed LLM, embedding, and STT providers in `config.yml` to OpenAI and Deepgram. - Removed read-only flag from `config.yml` in Docker Compose files to allow UI configuration saving. - Updated memory configuration endpoint to accept plain text for YAML input. * Update transcription job handling to format speaker IDs - Changed variable name from `speaker_name` to `speaker_id` for clarity. - Added logic to convert integer speaker IDs from Deepgram to string format for consistent speaker labeling. * Remove loading of backend .env file in test environment setup - Eliminated the code that loads the .env file from the backends/advanced directory, simplifying the environment configuration for tests. * Enhance configuration management and setup wizard - Updated README to reflect the new setup wizard process. - Added functionality to load and save `config.yml` in the setup wizard, including default configurations for LLM and memory providers. - Improved user feedback during configuration updates, including success messages for configuration file updates. - Enabled backup of existing `config.yml` before saving changes. * Enhance HTTPS configuration in setup wizard - Added functionality to check for existing SERVER_IP in the environment file and prompt the user to reuse or enter a new IP for SSL certificates. - Improved user prompts for server IP/domain input during HTTPS setup. - Updated default behavior to use existing IP or localhost based on user input. - Changed RECORD_ONLY_ENROLLED_SPEAKERS setting in the .env template to false for broader access. * Add source parameter to audio file writing in websocket controller - Included a new `source` parameter with the value "websocket" in the `_process_batch_audio_complete` function to enhance audio file context tracking. * Refactor error handling in system controller and update memory config routes - Replaced ValueError with HTTPException for better error handling in `save_diarization_settings` and `validate_memory_config` functions. - Introduced a new Pydantic model, `MemoryConfigRequest`, for validating memory configuration requests in the system routes. - Updated the `validate_memory_config` endpoint to accept the new request model, improving input handling and validation. --------- Co-authored-by: 0xrushi <6279035+0xrushi@users.noreply.github.com>
* obsidian support * neo4j comment * cleanup code * unused line * unused line * Fix MemoryEntry object usage in chat service * comment * feat(obsidian): add obsidian memory search integration to chat * unit test * use rq * neo4j service * typefix * test fix * cleanup * cleanup * version changes * profile * remove unused imports * Refactor memory configuration validation endpoints - Removed the deprecated `validate_memory_config_raw` endpoint and replaced it with a new endpoint that accepts plain text for validation. - Updated the existing `validate_memory_config` endpoint to clarify that it now accepts JSON input. - Adjusted the API call in the frontend to point to the new validation endpoint. * Refactor health check model configuration loading - Updated the health check function to load model configuration from the models registry instead of the root config. - Improved error handling by logging warnings when model configuration loading fails. --------- Co-authored-by: 0xrushi <6279035+0xrushi@users.noreply.github.com>
Adds COPY src/ src/ step after dependency installation to ensure all source files are available in the Docker image. This improves build caching while ensuring complete source code is present.
* Enhance configuration management and add new setup scripts - Updated .gitignore to include config.yml and its template. - Added config.yml.template for default configuration settings. - Introduced restart.sh script for service management. - Enhanced services.py to load config.yml and check for Obsidian/Neo4j integration. - Updated wizard.py to prompt for Obsidian/Neo4j configuration during setup and create config.yml from template if it doesn't exist. * Refactor transcription providers and enhance configuration management - Updated Docker Compose files to include the new Neo4j service configuration. - Added support for Obsidian/Neo4j integration in the setup process. - Refactored transcription providers to utilize a registry-driven approach for Deepgram and Parakeet. - Enhanced error handling and logging in transcription processes. - Improved environment variable management in test scripts to prioritize command-line overrides. - Removed deprecated Parakeet provider implementation and streamlined audio stream workers. * Update configuration management and enhance file structure, add test-matrix (#237) * Update configuration management and enhance file structure - Refactored configuration file paths to use a dedicated `config/` directory, including updates to `config.yml` and its template. - Modified service scripts to load the new configuration path for `config.yml`. - Enhanced `.gitignore` to include the new configuration files and templates. - Updated documentation to reflect changes in configuration file locations and usage. - Improved setup scripts to ensure proper creation and management of configuration files. - Added new test configurations for various provider combinations to streamline testing processes. * Add test requirements and clean up imports in wizard.py - Introduced a new `test-requirements.txt` file to manage testing dependencies. - Removed redundant import of `shutil` in `wizard.py` to improve code clarity. * Add ConfigManager for unified configuration management - Introduced a new `config_manager.py` module to handle reading and writing configurations from `config.yml` and `.env` files, ensuring backward compatibility. - Refactored `ChronicleSetup` in `backends/advanced/init.py` to utilize `ConfigManager` for loading and updating configurations, simplifying the setup process. - Removed redundant methods for loading and saving `config.yml` directly in `ChronicleSetup`, as these are now managed by `ConfigManager`. - Enhanced user feedback during configuration updates, including success messages for changes made to configuration files. * Refactor transcription provider configuration and enhance setup process - Updated `.env.template` to clarify speech-to-text configuration and removed deprecated options for Mistral. - Modified `docker-compose.yml` to streamline environment variable management by removing unused Mistral keys. - Enhanced `ChronicleSetup` in `init.py` to provide clearer user feedback and updated the transcription provider selection process to rely on `config.yml`. - Improved error handling in the websocket controller to determine the transcription provider from the model registry instead of environment variables. - Updated health check routes to reflect the new method of retrieving the transcription provider from `config.yml`. - Adjusted `config.yml.template` to include comments on transcription provider options for better user guidance. * Enhance ConfigManager with deep merge functionality - Updated the `update_memory_config` method to perform a deep merge of updates into the memory configuration, ensuring nested dictionaries are merged correctly. - Added a new `_deep_merge` method to handle recursive merging of dictionaries, improving configuration management capabilities. * Refactor run-test.sh and enhance memory extraction tests - Removed deprecated environment variable handling for TRANSCRIPTION_PROVIDER in `run-test.sh`, streamlining the configuration process. - Introduced a new `run-custom.sh` script for executing Robot tests with custom configurations, improving test flexibility. - Enhanced memory extraction tests in `audio_keywords.robot` and `memory_keywords.robot` to include detailed assertions and result handling. - Updated `queue_keywords.robot` to fail fast if a job is in a 'failed' state when expecting 'completed', improving error handling. - Refactored `test_env.py` to load environment variables with correct precedence, ensuring better configuration management. * unify tests to robot test, add some more clean up * Update health check configuration in docker-compose-test.yml (#241) - Increased the number of retries from 5 to 10 for improved resilience during service readiness checks. - Extended the start period from 30s to 60s to allow more time for services to initialize before health checks commence. * Add step to create test configuration file in robot-tests.yml - Introduced a new step in the GitHub Actions workflow to copy the test configuration file from tests/configs/deepgram-openai.yml to a new config/config.yml. - Added logging to confirm the creation of the test config file, improving visibility during the test setup process. * remove cache step since not required * coderabbit comments * Refactor ConfigManager error handling for configuration file loading - Updated the ConfigManager to raise RuntimeError exceptions when the configuration file is not found or is invalid, improving error visibility and user guidance. - Removed fallback behavior that previously returned the current directory, ensuring users are explicitly informed about missing or invalid configuration files. * Refactor _find_repo_root method in ConfigManager - Updated the _find_repo_root method to locate the repository root using the __file__ location instead of searching for config/config.yml, simplifying the logic and improving reliability. - Removed the previous error handling that raised a RuntimeError if the configuration file was not found, as the new approach assumes config_manager.py is always at the repo root. * Enhance speaker recognition service integration and error handling (#245) * Enhance speaker recognition service integration and error handling - Updated `docker-compose-test.yml` to enable speaker recognition in the test environment and added a new `speaker-service-test` service for testing purposes. - Refactored `run-test.sh` to improve the execution of Robot Framework tests from the repository root. - Enhanced error handling in `speaker_recognition_client.py` to return detailed error messages for connection issues. - Improved error logging in `speaker_jobs.py` to handle and report errors from the speaker recognition service more effectively. - Updated `Dockerfile` to copy the full source code after dependencies are cached, ensuring all necessary files are included in the image. * Remove integration tests workflow and enhance robot tests with HF_TOKEN verification - Deleted the `integration-tests.yml` workflow file to streamline CI processes. - Updated `robot-tests.yml` to include verification for the new `HF_TOKEN` secret, ensuring all required secrets are checked before running tests. * Fix key access in system admin tests to use string indexing for speakers data * Refactor Robot Framework tests and enhance error handling in memory services - Removed the creation of the test environment file from the GitHub Actions workflow to streamline setup. - Updated the Robot Framework tests to utilize a unified test script for improved consistency. - Enhanced error messages in the MemoryService class to provide more context on connection failures for LLM and vector store providers. - Added critical checks for API key presence in the OpenAIProvider class to ensure valid credentials are provided before proceeding. - Adjusted various test setup scripts to use a centralized BACKEND_DIR variable for better maintainability and clarity. * Refactor test container cleanup in run-robot-tests.sh - Updated the script to dynamically construct container names from docker-compose services, improving maintainability and reducing hardcoded values. - Enhanced the cleanup process for stuck test containers by utilizing the COMPOSE_PROJECT_NAME variable. * Enhance run-robot-tests.sh for improved logging and cleanup - Set absolute paths for consistent directory references to simplify navigation. - Capture container logs, status, and resource usage for better debugging. - Refactor cleanup process to utilize dynamic backend directory references, improving maintainability. - Ensure proper navigation back to the tests directory after operations. * Add speaker recognition configuration and update test script defaults - Introduced speaker recognition settings in config.yml.template, allowing for easy enable/disable and service URL configuration. - Updated run-robot-tests.sh to use a test-specific configuration file that disables speaker recognition for improved CI performance. - Modified deepgram-openai.yml to disable speaker recognition during CI tests to enhance execution speed. * Refactor speaker recognition configuration management - Updated docker-compose-test.yml to clarify speaker recognition settings, now controlled via config.yml for improved CI performance. - Enhanced model_registry.py to include a dedicated speaker_recognition field for better configuration handling. - Modified speaker_recognition_client.py to load configuration from config.yml, allowing for dynamic enabling/disabling of the speaker recognition service based on the configuration. * Add minimum worker count verification to infrastructure tests - Introduced a new keyword to verify that the minimum number of workers are registered, enhancing the robustness of health checks. - Updated the worker count validation test to include a wait mechanism for worker registration, improving test reliability. - Clarified comments regarding expected worker counts to reflect the distinction between RQ and audio stream workers. * Update configuration management and enhance model handling - Added OBSIDIAN_ENABLED configuration to ChronicleSetup for improved feature toggling. - Introduced speaker_recognition configuration handling in model_registry.py to streamline model loading. - Refactored imports in deepgram.py to improve clarity and reduce redundancy.
* Refactor configuration management in wizard and ChronicleSetup - Updated wizard.py to read Obsidian/Neo4j configuration from config.yml, enhancing flexibility and error handling. - Refactored ChronicleSetup to utilize ConfigManager for loading and verifying config.yml, ensuring a single source of truth. - Improved user feedback for missing configuration files and streamlined the setup process for memory and transcription providers. * Fix string formatting for error message in ChronicleSetup
#250) * added JWT issuers for audience auth for service interop and shared user accounts * amended default value in line wioth code
* Refactor configuration management in wizard and ChronicleSetup - Updated wizard.py to read Obsidian/Neo4j configuration from config.yml, enhancing flexibility and error handling. - Refactored ChronicleSetup to utilize ConfigManager for loading and verifying config.yml, ensuring a single source of truth. - Improved user feedback for missing configuration files and streamlined the setup process for memory and transcription providers. * Fix string formatting for error message in ChronicleSetup * Enhance chat configuration management and UI integration - Updated `services.py` to allow service restart with an option to recreate containers, addressing WSL2 bind mount issues. - Added new chat configuration management functions in `system_controller.py` for loading, saving, and validating chat prompts. - Introduced `ChatSettings` component in the web UI for admin users to manage chat configurations easily. - Updated API service methods in `api.ts` to support chat configuration endpoints. - Integrated chat settings into the system management page for better accessibility. * Refactor backend shutdown process and enhance chat service configuration logging - Updated `start.sh` to improve shutdown handling by explicitly killing the backend process if running. - Modified `chat_service.py` to enhance logging for loading chat system prompts, providing clearer feedback on configuration usage. - Added a new `chat` field in `model_registry.py` for better chat service configuration management. - Updated vector store query parameters in `vector_stores.py` for improved clarity and functionality. - Enhanced the chat component in the web UI to conditionally auto-scroll based on message sending status. * Return JSONResponse instead of raw result * Refactor headers creation in system admin tests * Make config.yml writable for admin updates
* Implement LLM services for llama.cpp integration - Added new service configuration for "llm-services" in `services.py` and `wizard.py`. - Updated `start.sh` to handle subcommands for service management. - Introduced `llamacpp` as a new LLM provider option in various files, including `init.py` and `config.py`. - Created Docker Compose setup for llama.cpp services in `docker-compose.yml`. - Added scripts for downloading models and managing environment configurations. - Enhanced observability with OpenTelemetry integration in memory and conversation jobs. - Updated default model configurations in `defaults.yml` for llama.cpp models. * use correct embedding endpoint * minor fixes probably should've been in other branch fahh
* init * fix * fix * remove
* edge code
* tiny fixes
* tiny fix again
* minor fix
* auto discover
* reworked
* fix
* missing file
* major fix
* input fix
* fix
* fix docker
* fix
* ui tweak
* Add support for optional static ESPHome device IP configuration
* Refactor audio streaming and authentication handling
- Updated `useAudioStreamer` to accept an options parameter for token refresh handling.
- Implemented automatic re-login on token expiration, updating the WebSocket connection with a new token.
- Enhanced error handling in WebSocket authentication to provide specific failure messages.
- Modified audio retrieval endpoints to support both Opus and WAV formats, improving efficiency and flexibility.
- Updated Docker configurations to replace Qdrant with Neo4j, adjusting environment variables and service dependencies accordingly.
- Cleaned up unused code and improved logging for better traceability.
* app reconnect update
* add app updates
* update package
* app: disable expo-updates and add file-based crash logging
Symptom: iPhone app worked for a day after install, then failed to
launch after backgrounding. No iOS .ips crash reports were produced.
Strong signal it's a JS-side startup hang (no native crash) caused by
expo-updates loading a bad/partial downloaded bundle at boot — reinstall
clears the cache and restores it for another day.
- Disable expo-updates via updates.enabled=false in app.json
(no code calls Updates.*, so OTA was not in active use)
- Add src/utils/logger.ts: file logger at
FileSystem.documentDirectory/chronicle-logs/chronicle-log.txt,
1 MB rotation, session header with updates state, ErrorUtils
global handler, unhandledrejection listener
- Add src/components/ErrorBoundary.tsx: root JS error boundary with
share/retry UI
- _layout.tsx: initialize logger + wrap in ErrorBoundary
- ConnectionLogContext: mirror every event to file logger
- diagnostics.tsx: Share Log File / Clear File buttons
- eas.json: add ascAppId for non-interactive TestFlight submits
- .easignore (root + app): exclude node_modules, android/app/build,
ios/Pods, build artifacts (project tarball 2.1 GB -> 154 MB)
* deps: upgrade Expo SDK 53 -> 55 and bump Xcode 26 image
- expo@~55.0.15
- @siteed/expo-audio-studio@^2.18.6 (2.18.1 pinned old
expo-modules-core@~2.4.0, incompatible with SDK 55)
- @types/react@~19.2.0, typescript@~5.9.2
- Regenerated ios/ via 'expo prebuild --clean'
- Removed newArchEnabled from app.json (default in SDK 55)
- Removed android.usesCleartextTraffic (duplicated by
expo-build-properties plugin)
- eas.json: pin testflight ios.image to
macos-sequoia-15.6-xcode-26.2 to satisfy Apple's Apr 28 2026
Xcode 26 upload requirement
* deps: bump react/react-dom to 19.2.5 so npm ci works on EAS
EAS Build runs strict 'npm ci' which rejected the lock file produced
by earlier 'npm install --legacy-peer-deps' commands (react-dom@19.2.5
pulled transitively by expo-router's radix-ui stack requires
react@^19.2.5, but root had react@19.2.0).
* metro: remove disableHierarchicalLookup (SDK 55 needs it)
expo-router in SDK 55 imports @expo/metro-runtime transitively from
node_modules/expo-router/node_modules/. With disableHierarchicalLookup=true
Metro can only resolve from the paths we explicitly listed, causing
'Unable to resolve module @expo/metro-runtime' during EAGER_BUNDLE.
This was the SDK 53-era monorepo recommendation; SDK 55's expo-router
deps require hierarchical lookup.
* fix: crash loop in index.tsx + logger now writes to disk on SDK 55
1) index.tsx: onDeviceConnect/onDeviceDisconnect referenced 'orchestrator'
and 'autoReconnect' which are declared later in the function (TDZ).
Accessing 'orchestrator.handleStartAudioListeningAndStreaming' in the
deps array caused 'Cannot read property ... of undefined' at render.
Introduce orchestratorRef/autoReconnectRef, assign them after the
hooks are declared. Pre-existing latent bug that became reproducible
on SDK 55.
2) logger.ts: Expo SDK 55 removed the default 'expo-file-system' runtime
in favour of 'expo-file-system/legacy' for the classic API (or the
new File/Directory classes). Calls to getInfoAsync etc. were throwing
on every write, so the file logger silently produced nothing.
Switch to 'expo-file-system/legacy' and add expo-file-system as a
direct dep so TS can resolve its types (it was only transitively
installed under expo/node_modules/).
* refactor: replace Neo4j with FalkorDB in configuration and codebase
- Updated environment variables and configuration files to replace Neo4j settings with FalkorDB.
- Modified Docker Compose files to use FalkorDB services instead of Neo4j.
- Adjusted application logic and routes to accommodate FalkorDB for entity management and knowledge graph functionalities.
- Introduced new graph client utilities for FalkorDB integration.
- Updated documentation to reflect changes in the architecture and service dependencies.
* feat: add View Logs menu item to wearable and relay menu bar apps
Captures recent log lines in an in-memory deque handler and exposes
them via a scrollable rumps.Window so users can inspect activity
without leaving the menu bar.
* fix: scrollable log dialog via NSScrollView+NSTextView
rumps.Window wraps an NSTextField, which doesn't scroll — long log
output was unreachable past the visible area. Replace with a native
NSAlert + NSScrollView containing an NSTextView (monospace, read-only,
scrolled to the latest entry on open).
* chore: drop havpe-relay/relay.sh, keep start.sh as single entrypoint
start.sh forwards args to main.py (supports subcommands like kickstart),
making the verbose-only relay.sh redundant. Also tracks logs.sh helper
for streaming ESPHome firmware logs.
* refactor: remove qdrant-test log commands from CI workflows
The logging commands for the qdrant-test service have been removed from the full-tests-with-api.yml, pr-tests-with-api.yml, and robot-tests.yml workflows to streamline log management and reduce unnecessary output during CI runs.
* feat(vault-sync): macOS menu bar app to sync Chronicle vault via Syncthing
Adds extras/vault-sync/, a rumps menu bar app (sibling of havpe-relay /
local-wearable-client) that runs a private headless Syncthing and pairs it
with the Chronicle server through the backend broker, so the per-user
conversation_docs vault can be opened in Obsidian on the Mac.
- syncthing_manager: owns local Syncthing process + REST config
- vault_core: backend discovery, JWT auth, /api/vault-sync/pair broker call
- menu_vault: status UI, choose folder, open-in-Obsidian, re-pair
- main/service/start.sh: launchd install pattern
Server-side pieces (compose service + broker router) are deployed separately.
* fix(vault-sync): drop removed --no-default-folder flag for Syncthing v2
Syncthing v2.1.1 removed --no-default-folder, so the local instance exited
immediately with 'unknown flag' and the menu bar app only surfaced a generic
'did not become ready in time' timeout (subprocess output went to DEVNULL).
- Drop the obsolete flag and pass --gui-apikey explicitly
- Capture subprocess output to syncthing.log instead of DEVNULL
- Detect early process exit in _wait_ready and report the exit code + log path
* feat(discovery): loud backend URL resolution across menu bar apps
Adds discovery.resolve_backend_url(), which logs *how* the backend URL was
chosen (explicit env > minidisc discovery > default) and, on fallback, *why*
discovery didn't apply — minidisc missing, no tailscaled socket (normal on
macOS GUI Tailscale), or nothing advertised. No more silent localhost fallback.
Wires vault-sync, havpe-relay, and local-wearable-client through it so all
three surface the reason in their logs / View Logs.
* docs(vault-sync): document macOS BACKEND_URL gotcha and verified server setup
- README: macOS GUI Tailscale has no tailscaled socket -> set BACKEND_URL to the
MagicDNS name; Mac needs only BACKEND_URL + email/password; force-recreate (not
restart) the backend after adding server env / editing the single-file discovery.py
mount; added a broker-chain verification curl.
- overview.md: list extras/vault-sync in components + repo structure.
* feat(vault-sync): server-side Syncthing service + pairing broker
Completes the server half of vault sync (Mac app shipped earlier):
- docker-compose: vault-syncthing service (profile vault-sync) sharing
data/conversation_docs at /vaults; backend gets VAULT_SYNC_* env to drive it.
- routers/modules/vault_sync_routes.py: /api/vault-sync/info + /pair broker.
JWT-auth'd; configures the server Syncthing over REST (per-user folder
vault-{user_id}, adds the Mac device) so the Mac never needs the server key.
- .env.template: VAULT_SYNC_API_KEY / VAULT_SYNC_ADDRESS / PUID/PGID.
* holy commit
* asr providers
* feat(vault-sync): ignore .obsidian dir in Syncthing folders
Obsidian's per-vault workspace/config dir is local state, not content
worth syncing. Set .stignore patterns (.obsidian, .obsidian/**) via the
Syncthing REST API when upserting the folder on both the Mac client
(syncthing_manager) and the server broker (vault_sync_routes).
* feat(havpe): play notification tones on device via backend downlink
Wake-word arm and end-of-turn play tones on the HAVPE device:
- Relay serves bundled HA Voice PE tones (CC-BY 4.0) from a local on-LAN
HTTP server (tone_server.py) and handles a new play-tone backend message.
- Backend forwards device:downlink:{client_id} Redis pub/sub frames down the
device WebSocket via a new subscribe_to_device_downlink task, giving any
backend component a channel to push control messages to a specific device.
The wakeword-service publish side lives in that (untracked) service.
* feat(havpe): relay serves backend TTS audio on the LAN (play-audio audio_b64)
The device can't reach the backend (LAN-only vs Tailscale), so the relay now
accepts inline base64 audio in play-audio messages, writes it to a uniquely
named file, and serves it from the local tone HTTP server. Raises the
backend->relay WS frame limit to 16 MiB for larger TTS payloads.
Backend dispatcher synthesizes the Hermes reply via the TTS service and pushes
it down device:downlink:{client_id} (that side lives in the untracked backend
wakeword dispatcher).
* gemma misc files asr
* hermes
* wakeword plumbing
* app update
* fix(app): bump expo-audio to ~55.0.14 for Expo SDK 55 compatibility
expo-audio@0.4.9 referenced EXFatal/EXErrorWithMessage which were removed
from ExpoModulesCore in SDK 55, breaking the iOS build (XCODE_BUILD_ERROR:
cannot find 'EXFatal' in scope). Align to the SDK-55 expected version.
audioPlayback.ts (only consumer) is API-compatible; 0 TS errors.
* update
* fix(app): pin expo-asset to SDK 55 (~55.0.17), was pulled to 56.0.15
Adding expo-audio (loose 'expo-asset: *' peer range) let npm resolve
expo-asset to 56.0.15 — an SDK 56 native module in an SDK 55 app
(expo-modules-core 55.0.22). The ABI mismatch crashed the JS bridge at
startup (white screen on launch). Pin to the SDK-55 line.
* fix(vault-sync): detach stale same-path folders on pair + surface folder errors
Re-pairing with a new folder id (e.g. after the backend re-creates the
admin user with a new ObjectId following a data reset) left the previous
folder bound to the same local vault dir. Syncthing refuses two folders
sharing a directory, so sync silently wedged. ensure_folder now detaches
any other folder bound to the target path before upserting the current one.
Also replace folder_completion with an error-aware folder_status: it no
longer reports a misleading 100% when globalBytes==0, and surfaces
folder-level/item errors in the menu so a broken sync stops showing as
"In sync".
* fix(vault-sync): surface Syncthing errors in logs; prevent case-collision notes
vault-sync menu:
- SyncthingManager.collect_errors() reads /rest/system/error and
/rest/folder/errors so the real cause (e.g. case collisions, pull
failures) reaches the menu's View Logs instead of staying buried.
- refresh_status() logs new Syncthing errors (deduped) into the log
buffer; menu status line shows a truncated message, full text in logs.
backend vault agent:
- VaultTools._resolve_ci() maps note paths case-insensitively onto
existing files before write/edit/read/rename, so the agent reuses an
existing note (People/hermes.md) instead of minting a case-variant
sibling (People/Hermes.md) that collides irrecoverably on
case-insensitive (macOS/Windows) Syncthing clients.
* feat(tones): single-source wake-word tones via inline play-audio
The wake-word service is now the only place tone audio lives. It sends
tones (and TTS) to every client — HAVPE relay, phone app, web UI — as
inline `play-audio` bytes that each client decodes and plays. This removes
the relay's duplicate bundled tones and the dead `play-tone` path (which
had no producer left after the service switched to play-audio).
- wakeword-service: add armed.wav/done.wav (un-ignored via .gitignore
negation so they're baked into the image)
- relay: drop the `play-tone` branch + `tone_url`/`TONE_FILES`; tone_server
now only stages backend-pushed audio to a runtime `audio_cache/` dir
served on the LAN (renamed from the old bundled-tones dir)
- delete extras/havpe-relay/tones/ (moved to wakeword-service)
* mega commit cuz im a terrible developer
* feat(vault-graph-vr): WebXR 3D vault graph viewer for Quest
Explore the memory vault (notes + [[wikilinks]]) as a 3D force-directed
graph in the Quest browser via WebXR. Point a controller at a node/link and
fly to it (smooth/snap) to read the note. R3F v8 + @react-three/xr v6 +
r3f-forcegraph + Vite/TS. Includes a vault scanner (build-graph.mjs), a
sample vault, and a README. Build/typecheck/dev-serve verified; in-headset
interaction not yet device-tested.
* feat(vault-graph-vr): node grab/anchor, reader panel, passthrough, 360° capture
Interaction & navigation:
- Controller raycast hover + trigger to open a node; hold B to drag nodes
(d3 sim reheats so neighbours react), double-tap B to anchor/unanchor.
Haptics ramp with edge stretch and hard-stop against anchored neighbours.
- Reader panel anchored toward the viewer with clickable wikilink "chips"
that smoothly fly you to the linked note.
- Start inside the graph (GRAPH_POSITION at head height, full 360).
Environment & tooling:
- AR entry with toggleable passthrough (room) vs opaque Backdrop void + stars.
- 360° equirect capture (L-stick click / desktop button) POSTed to dev server.
- Debug HUD + error relay piping console/uncaught errors to ./captures/debug.log
via a vite /__log + /__capture endpoint.
- Make SpriteText labels non-raycastable (Sprite.raycast crashed XR pointer input).
gitignore captures/ (in-headset debug screenshots/recordings/logs).
* feat(wearable-client): macOS screen + accessibility capture (stage 1)
Add a pure-PyObjC capture module to the local-wearable-client menu bar app:
1 fps full-display screenshot via CGDisplayCreateImage, focused-window
app/title read via the Accessibility API (AXUIElement), JPEGs written to
~/ChronicleCaptures. No Swift required.
- screen_capture.py: ScreenCaptureManager (start/stop/toggle), TCC permission
prompts (Screen Recording + Accessibility), standalone __main__ for testing
- menu_app.py: "Screen Capture" toggle + "Grant Capture Permissions" items
- pyproject.toml: pyobjc-framework-Quartz + ApplicationServices (darwin only)
* feat(wearable-client): capture every active display (one JPEG per screen)
Enumerate all active displays via CGGetActiveDisplayList and write one JPEG
per screen each tick, suffixed _i (index 0 = main display). Previously only
CGMainDisplayID was captured, which on a multi-monitor setup grabbed only the
menu-bar display.
* feat(wearable-client): ScreenCaptureKit capture + .app bundle (stage 2)
Upgrade screen capture from the deprecated CGDisplayCreateImage to
ScreenCaptureKit (SCScreenshotManager) behind a backend abstraction, with the
CoreGraphics path kept as a fallback for macOS < 14. Captures every active
display at native pixel resolution.
Add a py2app bundle so TCC permission grants (Screen Recording, Accessibility,
Microphone, Bluetooth) attach to a real app identity (ai.chronicle.wearable)
instead of the launching terminal/interpreter:
- setup_app.py: py2app config with Info.plist usage strings, LSUIElement,
unsandboxed (required for AX reads of other apps)
- build_app.sh: build + codesign helper (ad-hoc, or self-signed via CODESIGN_ID
so grants persist across rebuilds)
- CAPTURE.md: what's captured, permission model, build/signing steps
* fix(wearable-client): build .app from isolated bundle/ dir (py2app)
py2app rejects the package's PEP 621 [project].dependencies (auto-promoted to
install_requires), failing the build. Move setup_app.py into bundle/ — a dir
with no pyproject.toml — and add the package dir to sys.path so py2app's module
graph still finds menu_app/screen_capture/main. build_app.sh now builds there
and renames menu_app.app -> "Chronicle Wearable.app".
Also document the -3801 "user declined TCCs" case (cached Screen Recording
denial for the launching terminal) and the tccutil reset / manual-grant fix.
* feat(wearable-client): run capture under launchd agent, drop py2app bundle
py2app can't freeze uv's standalone Python (fails on zlib.__file__ — it expects
a framework build), and freezing would also break main.py's __file__-relative
config loading. Drop the bundle path entirely and deploy via the project's
existing launchd agent (./start.sh install), which runs the source directly.
Under launchd there's no terminal, so TCC attaches Screen Recording /
Accessibility grants to the agent's own Python (its own identity), not to
Cursor/the terminal. Add CAPTURE_AUTOSTART to optionally begin capture on agent
launch once Screen Recording is granted. Rewrite CAPTURE.md around this flow
(grant via the menu's "Grant Capture Permissions", kickstart, .python-version
pin to keep the grant stable).
Removes build_app.sh and bundle/setup_app.py.
* feat(wearable-client): metadata sidecar (events.jsonl) + OCR + analytics
Capture richer per-tick context alongside screenshots and write it to a
per-day events.jsonl, plus an analyze.py for app/title/URL time reports.
screen_capture.py:
- read_focused_window now also returns URL (AXURL, browsers/doc apps),
focused subrole, and selected-text length (length only, not content)
- user_idle_seconds() via CGEventSourceSecondsSinceLastEventType
- optional Apple Vision OCR (ocr_jpeg); writes .txt sidecars, opt-in
- ScreenCaptureManager writes one JSON event per tick to events.jsonl
(rotated by date); new write_events/ocr flags + --no-events/--ocr CLI
menu_app.py: CAPTURE_OCR=1 enables OCR under the agent.
analyze.py: app-time analytics over events.jsonl (--by app/title/url,
--days/--date, idle bucketing, gap-aware). Pure stdlib.
CAPTURE.md: document the schema, OCR, analytics, and privacy.
* feat(wearable-client): bound capture storage (dedup + idle-skip + retention)
Raw 1fps full-res capture is ~25 GB/day. Keep the tiny events.jsonl timeline
forever (it powers analytics) and manage only the screenshots with three simple
rules:
- dedup: SHA-1 each frame; if identical to the last stored frame for that
display, don't rewrite — the event reuses the file and marks changed=false
(also skips re-OCR). Bounds static/AFK screens.
- skip-idle: after CAPTURE_SKIP_IDLE_SECS (default 90s) of no input, skip
screenshots entirely; still log the event (screenshots=skipped_idle).
- retention: sweep on start + hourly, delete .jpg/.txt older than
CAPTURE_RETENTION_DAYS (default 14); events.jsonl is never deleted.
Config via env (agent) or flags (standalone): CAPTURE_NO_DEDUP,
CAPTURE_SKIP_IDLE_SECS, CAPTURE_RETENTION_DAYS / --no-dedup, --skip-idle,
--retention-days. CAPTURE.md documents the strategy, the read-back contract,
and the advanced path (HEVC video chunks + perceptual hashing) with references
to ActivityWatch/Screenpipe.
* feat(wearable-client): skip capture while screen locked; refine storage docs
Add screen_is_locked() (CGSessionCopyCurrentDictionary) and skip screenshots
when the screen is locked/screensavered, logged as screenshots=skipped_locked
(same path as idle-skip). Both Screenpipe and Omi gate on lock state.
Refine CAPTURE.md storage references with the concrete findings from the
ActivityWatch + Screenpipe source review: ActivityWatch's heartbeat-merge +
no-retention model, Screenpipe's JPEG->H.265 compaction, two dedup layers, and
14-day default retention (matching ours). Document the JPEG-then-compact-to-video
pattern as the recommended next lever for active-use storage.
* feat(wearable-client): half-res frames + thumbnail dedup hash + settings UI
Full-res Retina frames ran up to ~1.4MB each. Save at a fraction of native
resolution (default 0.5 = half) — ScreenCaptureKit downscales in the compositor
so the full-res bitmap is never produced; CoreGraphics fallback scales after grab.
Dedup now hashes a small downscaled thumbnail (max dim 256px) instead of the
full JPEG — cheaper to hash and robust to trivial pixel noise.
Add a "Capture Settings…" menu item: a native form to edit resolution,
idle-skip, retention, dedup thumbnail size, and the dedup/OCR toggles. Changes
apply live to the running capture and persist to .env across restarts.
* feat(wearable-client): show running version (git hash + date) in menu
Adds a non-clickable "Version: <short-hash> (date)" line at the bottom of the
menu so you can confirm at a glance which build is running — useful after a
reinstall to verify the agent picked up new code. Falls back to this file's
mtime when git isn't available.
* kitchen sink commit. Kokoro TTS support and enhance backend configuration, podman
* edge deployment
* defaults
* fix(wizard): guard Tailscale prereq in join-cluster flow
The 'Join a cluster' flow jumped straight to minidisc discovery without
checking Tailscale was up, so a missing/down Tailscale produced a misleading
'no backend discovered on the Tailnet'. Check up front and name the real
cause: abort with install / 'sudo tailscale up' guidance when Tailscale is
absent or not connected (offer continue-anyway for the manual-URL case).
* updates
* feat(boot): autostart container stack on boot via chronicle-stack systemd unit
Rootless Podman is daemonless, so unlike Docker nothing re-applies `restart:`
policies after a reboot — the stack stays down. (Podman's own
podman-restart.service only matches restart-policy=always, not unless-stopped.)
Add a `chronicle-stack` systemd *user* oneshot that runs `services.py start --all`
on boot (same path as ./start.sh, respecting the config.yml enabled set), ordered
After=chronicle-service-manager.service. It installs alongside the node agent via
`manager install` / the wizard's "Auto-start on boot" prompt, enabled for boot only
(install does not trigger a full stack `up`). No compose-file edits needed.
- services.py: richer _SYSTEMD_UNITS config (Type/restart/oneshot/after/enable_now),
generalized _write_systemd_unit, enable_now-aware _install_systemd_unit, status line
- wizard.py: update "Auto-start on boot" copy (containers no longer self-revive)
- Docs: document the unit in init-system.md and podman.md reboot-persistence caveat
* fix(speaker): serve web-ui over plain HTTP behind Caddy, drop basic-ssl
The speaker web-ui ran its vite dev server over HTTPS via @vitejs/plugin-basic-ssl,
with Caddy proxying to it over TLS (tls_insecure_skip_verify). basic-ssl caches a
self-signed cert in node_modules; if vite is SIGTERM'd mid-generation it leaves a
0-byte _cert.pem that it then reuses forever → TLS handshake failure → web-ui
unhealthy → caddy's `depends_on: service_healthy` blocked `up` → services.py 120s
timeout → SIGTERM re-poisons the cert. The whole speaker stack needed a manual cert
wipe on every start.
Remove the self-signed-TLS dance entirely and match the advanced backend's webui-dev:
the dev server runs plain HTTP and Caddy terminates TLS (Tailscale/Let's Encrypt
cert) and reverse-proxies over HTTP.
- webui/vite.config.ts: drop basicSsl plugin + server.https
- Caddyfile(.template): reverse_proxy web-ui over plain http (no tls transport)
- docker-compose.yml: drop caddy's depends_on web-ui (lazy upstream; can't block up)
- init.py: keep REACT_UI_HTTPS=false even when HTTPS is on (it drives vite + the
healthcheck); track Caddy-on via HTTPS_CERT_MODE for the summary/next-steps
* update config manager and llm services
* update system page
* update .gitignore
* update wizard flow
* update wizard flow
* update wizard flow
* updates
* more updates
* Connection resilience + auth/network UX
App:
- BLE + WS auto-reconnect: persistent retry (never permanently give up, never
forget the device on one failure), zombie-socket ping/pong detection,
foreground/relaunch (AppState) recovery.
- Central auth manager (services/auth.ts): SecureStore-backed secrets, silent
token refresh everywhere (fetchAuthed), logout vs forget-account split.
- Connection Doctor probe ladder in BackendStatus: not-configured / offline /
backend-down / unreachable, with SM-probe disambiguation and Tailscale-aware
guidance; QR-first layout.
- QR JSON bundle parsing, service-manager client (serviceManager.ts) with
backend-proxy + direct transports, collapsible node-grouped Network Overview,
and backend-URL recovery from stored SM creds.
Backend / clients:
- WebSocket controller replies {type:"pong"} at both ping sites.
- Dashboard System page QR emits {backendUrl, serviceManagerUrl} JSON bundle.
- Wearable client + HAVPE relay: backend-WS reconnect with capped backoff and
mid-session JWT refresh; HAVPE ESPHome API mid-session recovery.
Claude-Session: https://claude.ai/code/session_01AUY5MWM6zdKDbvCPksMxBq
* app updates
* clean up memory systems
* updates to docs
* update yee
* Add device_audio module for Opus streaming to ESP32 devices
* Elato: newest-wins device playback (cancel superseded Opus clip)
A new play-audio now cancels the Opus clip still streaming to the same
device instead of interleaving frames on the socket (which sounded like
two replies alternating). Tracked per client_id so it holds across a
stale + fresh downlink subscriber; the stream runs as a background task
so the downlink loop stays free to supersede it.
* Remove CAPTURE.md from version control
* websocket connection
* web view updates
* default plugins
* Bump app version to 1.0.7
* Move backend setup/account into Settings gear; inline reconnect indicator
- Add AppSettingsProvider so home + settings share one settings instance
- New Settings screen (gear in header) holds backend pairing, login,
system admin, and network overview
- Home screen shows live status + a setup CTA only when unpaired/logged out
- Replace full-screen auto-reconnect takeover with inline spinner banner
in the Connection tab
- Bump app version to 1.0.8
* feat(speaker): robust diarization via cluster-then-identify + forced alignment
Fix over-identification where a 2-person conversation was labeled as many
speakers (short segments spuriously matching a growing 42-speaker gallery,
plus cross-chunk label fragmentation from the 2-min diarization cap).
- audio_backend: replace label-string chunk stitching with embedding-based
global speaker reconciliation — cluster chunk-local centroids (average
linkage, same-chunk cannot-link sentinel, max_speakers hard cap). Keeps
chunking to bound pyannote's O(N^2) CPU clustering while producing
globally-consistent labels.
- identification: cluster-then-identify — one pooled centroid decision per
diarized speaker (not per segment), with an open-set best-vs-runner-up
margin guard and exclusive assignment.
- unified_speaker_db: add identify_with_candidates() returning ranked
candidates for margin/exclusive logic; identify() behavior unchanged.
- asr-services: expose /align endpoint (existing MMS_FA forced aligner),
reading WAV via stdlib wave to avoid the torchcodec dependency;
per-segment alignment with proportional fallback.
- backend: synthesize word timestamps via /align when a provider (e.g.
VibeVoice) emits segments without words, routing word-less conversations
onto the full pyannote re-diarization path instead of per-segment id.
Result on the test conversation: 10 labels (incl. 4 spurious identities)
-> 2 clean speakers (ankush, vipul g) + a few stray segments.
Claude-Session: https://claude.ai/code/session_01CkoBkd7ZM3SPUBCHctNKRt
* feat(speaker): wire reconciliation/identify knobs to diarization config
Make the chunk-reconciliation and open-set identification parameters tunable
from config instead of hardcoded:
- reconciliation_threshold (default 0.4): min cosine similarity to merge
chunk-local centroids into one global speaker
- identify_margin (default 0.1): open-set best-vs-runner-up gap guard
- exclusive (default true): one enrolled speaker per diarized speaker
Flows config (diarization settings) -> speaker_recognition_client form fields
-> /v1/diarize-identify-match Form params -> async_diarize / cluster-identify.
max_speakers was already wired; it caps the global speaker count after
reconciliation. defaults lowered the async_diarize reconciliation default
0.5 -> 0.4 to merge same-speaker chunks more readily.
Claude-Session: https://claude.ai/code/session_01CkoBkd7ZM3SPUBCHctNKRt
* fix(speaker): guard chunk reconciliation against NaN centroids
Silent/degenerate segments embed to a zero vector, which the embedder normalizes
to NaN (0/0). A NaN centroid produced NaN cosine distances, and sklearn's
AgglomerativeClustering rejects NaN -> ValueError -> HTTP 500 in
diarize-identify-match (seen reprocessing streaming-only conversations).
- _embed_local_speakers: drop non-finite per-segment embeddings; skip a local
speaker entirely if it has no finite embedding (and guard zero-norm centroids).
- _reconcile_chunk_speakers: nan_to_num the distance matrix as a safety net so a
stray non-finite value becomes "maximally far" instead of crashing clustering.
Claude-Session: https://claude.ai/code/session_01CkoBkd7ZM3SPUBCHctNKRt
* Recognize Elato devices in BLE discovery filters
Add 'elato' to the wearable name filters so the OMI-compatible Elato BLE
peripheral is auto-discovered alongside OMI/Friend/Neo, in both the macOS
menu-bar client (main.py, menu_app.py) and the mobile app. Classify Elato
as an OMI-type device (it speaks the OMI GATT contract) and update the
filter toggle labels.
* Forward backend Opus downlink to Elato BLE speaker
Plumbs the backend's existing Opus speaker downlink (speak-start / binary Opus /
speak-end, plus speak-stop) through the relay to the device's new BLE speaker
characteristic, so Elato gets TTS/playback over BLE the way it already does over WiFi.
- friend-lite-sdk: add ELATO_SPEAKER_CHAR_UUID + speaker opcodes; OmiConnection gains
speaker_start/end/stop and write_speaker_audio (MTU-fragmented write-without-response).
- local-wearable-client: receive_handler now forwards binary Opus frames and
speak-start/end/stop to the BLE speaker char (threaded the OmiConnection through
stream_to_backend); only for OmiConnection devices (OMI/Neo have no speaker).
- backend: guard websocket.send with WebSocketState.CONNECTED in the interim-result
and device-downlink subscribers, fixing the 'websocket.send after websocket.close'
ASGI error when a result/downlink races the socket close.
* big chungus commit
* Enhance conversation controller to compute unique speakers and segment count from active transcript version. Add TIMING annotation type and related API endpoints for adjusting segment timings. Implement waveform data fetching and region editing components in the web UI for improved audio segment management.
* cleaner
* refactor: hoist function-level imports to module top
Sweep of the mid-function-import anti-pattern across the backend,
extras services, edge/root scripts, and test libs (~350 sites hoisted
or deduped across 114 files, net -150 lines).
- Hoist stdlib, light third-party, and internal imports to module top
per the project import guidelines; dedupe repeated per-function
imports (e.g. rq.registry x6 in queue_routes, plugin_service x13 in
system_controller)
- Keep genuinely-lazy imports and document each with a comment:
circular-dependency breakers (queue_controller<->workers,
conversation_jobs<->transcription_jobs, chronicle->agent->llm_client,
speaker-recognition router DI), optional deps (opentelemetry,
langfuse, minidisc), heavy ML model loads, macOS-only AppKit/rumps,
torch-less ASR provider images, and init-ordering in app_factory /
models/job / rq_worker_entry
- Verified: fresh-process import sweep of all changed backend modules
(no new failures vs baseline), ruff F401/F811/F821 vs HEAD (0 new,
~80 pre-existing unused imports eliminated), black + isort, and the
no-API robot suite (110 pass; 18 failures are pre-existing stale
tests for removed knowledge-graph/falkordb endpoints, RQ worker
count, and the processing-status rename)
* feat: plugin degraded state + background recovery loop
Plugins whose external dependency is unreachable (e.g. Home Assistant
on a powered-off server) now degrade instead of failing permanently:
- New PluginConnectivityError -> DEGRADED health state (vs FAILED for
real config/setup errors); system event recorded only on transition
so retry ticks don't spam the log
- Shared initialize_plugins() used by every plugin-router host
(FastAPI app, streaming worker, wakeword worker, RQ workers,
hot-reload) replaces four copies of the init loop
- run_plugin_recovery() background task: per-plugin exponential
backoff re-init (30s..600s) plus a 5-min health probe that demotes
initialized plugins whose health_check starts failing
- homeassistant plugin raises PluginConnectivityError on unreachable
HA and uses a 5s connect timeout
* feat: fallback LLM with one-shot retry on transport failures
defaults.fallback_llm names a model (default: OpenAI gpt-5-nano) that
llm_client wrappers retry against exactly once when the primary LLM
fails at the transport level (APIConnectionError, InternalServerError,
timeout) — auth/4xx config errors are not retried since the fallback
would not fix them.
- model_registry: get_fallback_llm_operation() resolves an operation
against defaults.fallback_llm via a new model_override param; skips
when unset, invalid, or identical to the primary model.
reasoning_effort "none" downgrades to "minimal" for pre-gpt-5.1
reasoning models that reject it
- health: /readiness reports fallback_llm status (non-critical)
- wizard: new "Fallback LLM" setup step with enable/disable and
model/key prompts; defaults.yml gains the fallback-llm model entry
* feat: segment deletion annotations + curated speaker enrollment
Two annotation-driven workflows:
Deletion annotations
- New DELETION annotation type: mark a transcript segment for removal,
staged as a pending correction and committed by /apply, which
re-derives a new transcript version with the segment dropped
(inserts are positioned against original indices first, then
deletions applied by object identity so indices stay valid)
- TranscriptEditor: per-segment delete toggle with pending-state UI
Curated speaker enrollment (replaces blunt annotation replay)
- GET /api/finetuning/enrollment-candidates builds a quality-gated,
per-speaker candidate list from the ACTIVE transcript version of
labelled conversations: >=3s duration, no cross-talk overlap with
another enrollable speaker, near-duplicate spans deduped; longest 5
clean clips per speaker pre-selected
- POST /api/finetuning/enroll-selected enrolls only user-promoted
clips, re-validating each span against the current active version
(guards a version change between review and submit), then marks the
source diarization annotations trained
- New EnrollmentCandidates review UI on the Finetuning page
* chore: satisfy pre-push formatting hooks (black, isort, eof-newline)
* fix: three latent bugs found during import sweep
- health_routes: stop constructing the memory service, transcription
provider, and model registry at import time. Memory-service creation
raises when LLM defaults are unconfigured, which killed every route in
routers.modules on import; all three are now acquired inside the
handlers (creation failure reports 'unavailable' instead of a 500).
- user_controller: delete_all_user_memories is async — running it in an
executor returned an un-awaited coroutine, so user deletion never
deleted memories and the count comparison would TypeError. Await it
directly.
- enroll_speaker: --list/--delete called list_speakers_with_url/
delete_speaker_with_url, which never existed (NameError). Thread
--service-url through list_speakers/delete_speaker instead.
Also drops now-dead unused imports in the touched files and updates the
data_audit_controller lazy-import comment to cite the real (still
present) package cycle rather than the removed side effect.
…se 1+2) Version truth is git describe on the checkout (updates.py). Nodes report it via the agent (/node + Tailnet advertise label); images bake CHRONICLE_BUILD_VERSION (compose build arg, set by services.py locally and CI on release) surfaced at /version. Updates: services.py update [--check|--tag|--prebuilt] moves the checkout (branch pull --rebase --autostash, or release-tag checkout) and rebuilds enabled services, rolling back to the previous commit if one fails to come up. The node agent exposes GET/POST /update (peer-forwarded like service actions) and restarts itself last; the backend proxies as /api/admin/update for the System page's per-node check/update controls.
main.py imports 'from service import ...' since the service-management CLI landed, but .dockerignore's allowlist never gained service.py — so a fresh image build crash-loops on ModuleNotFoundError while stale images (built before the import existed) keep working. Surfaced by the first rebuild on the rpi after moving it to dev.
'this node' is relative to the server, which reads wrong from any other device's browser (e.g. a phone). The badge marks the hub — say so.
a12b689 included the router registration (modules/__init__.py, api_router.py) but not the module itself, so the backend crashed on import at startup — this is what broke CI's chronicle-backend-test container on the last push.
…ker-count expectations The knowledge-graph feature (FalkorDB routes, wizard toggle) and the /api/admin/chat/config endpoints were removed in #332, but their tests were left behind — every one 404s in CI: - delete knowledge_graph_tests.robot, knowledge_graph_integration_test.robot and knowledge_graph_keywords.robot - health_tests: stop asserting the removed config.falkordb_host key - system_admin_tests: drop the three chat-config tests and the /api/admin/chat/config entry in the non-admin access list - test_wizard_defaults: drop select_knowledge_graph tests (function removed from wizard.py) Also sync expectations that drifted behind intentional refactors: - always_persist_audio_tests: processing_status is now the 3-state machine's 'active', not 'pending_transcription' - infra_tests: 10 RQ workers now (the dedicated memory worker was added alongside the 6 general + 3 audio persistence)
'Button Press Should Close Active Conversation' failed in every CI run since #332: the button_control rework maps single_press to stop_playback (barge-in) and double_press to close_conversation, and the 'actions:' override in plugins.test.yml was never read — load_plugin_config() only merges enabled/events/condition from config/plugins.yml, so the plugin ran with its own config.yml defaults. The conversation never closed and the WS eventually died with end_reason=websocket_disconnect. - test sends DOUBLE_PRESS (the close_conversation mapping) and documents where the mapping lives - plugins.test.yml: drop the dead actions block, note that this file is orchestration-only - plugin_service: warn when config/plugins.yml carries non-orchestration keys instead of silently dropping them Verified locally against real Deepgram: test passes.
…container exec - annotation_suggestions_tests: random email + teardown delete, so a leftover user from an aborted run can't 409 the re-run - test_env.py/redis_keywords: resolve the container engine from CONTAINER_ENGINE (default docker, so CI is unchanged) and derive container names with the engine's separator (podman-compose uses backend-test_redis-test_1, docker compose backend-test-redis-test-1)
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
| Metric | Count |
|---|---|
| ✅ Passed | 110 |
| ❌ Failed | 3 |
| 📊 Total | 113 |
📊 View Reports
GitHub Pages (Live Reports):
Download Artifacts:
- robot-test-reports-html-no-api - HTML reports
- robot-test-results-xml-no-api - XML output
No description provided.