Commit Graph

378 Commits

Author SHA1 Message Date
Christian Gick
5ad1d1d60c fix(e2ee): correct misleading log messages after KDF revert (MAT-144)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 08:29:34 +02:00
Christian Gick
911a48330f chore: Trigger rebuild 2026-03-10 08:27:09 +02:00
Christian Gick
30ade51d4a chore: Trigger rebuild 2026-03-10 08:21:23 +02:00
Christian Gick
7b563d39b3 chore: Trigger rebuild 2026-03-10 08:18:04 +02:00
Christian Gick
c61bcffec2 revert(e2ee): restore KDF_HKDF=1, KDF_RAW=0 causes PBKDF2 double-derivation (MAT-144)
KDF_PBKDF2=0 does NOT mean raw mode — libwebrtc applies its built-in
PBKDF2 on top of pre-derived keys, causing DEC_FAILED for audio too.
Revert to KDF_HKDF=1 (Rust applies HKDF, we pass raw base keys).

Keep diagnostic improvements:
- _derive_and_set_key() wrapper with logging
- Per-track type logging (audio vs video) in on_track_subscribed
- Frame size check in look_at_screen (detect E2EE failure)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 08:17:46 +02:00
Christian Gick
e63fc2b680 chore: Trigger rebuild 2026-03-09 17:06:23 +02:00
Christian Gick
d586ddfa6d fix(e2ee): pre-derive HKDF keys in Python instead of Rust FFI (MAT-144)
Switch from Rust-side HKDF (KDF_HKDF=1) to Python-side HKDF derivation
with raw key mode (KDF_RAW=0). This eliminates potential HKDF implementation
mismatches between Rust FFI and Element Call JS that caused video frame
decryption failures (audio worked, video showed 8x8 garbage frames).

Changes:
- Add _derive_and_set_key() helper that pre-derives HKDF then calls set_key()
- Set key_derivation_function=KDF_RAW (proto 0 = no Rust-side derivation)
- Replace all direct set_key() calls with _derive_and_set_key()
- Add per-track diagnostic logging (audio vs video)
- Add frame size check in look_at_screen (detect E2EE failure early)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 17:05:59 +02:00
Christian Gick
19a973b9eb chore: Trigger rebuild 2026-03-09 16:47:40 +02:00
Christian Gick
2b92b99292 fix(MAT-140): Add min resolution check for video frame capture
8x8 frames are encrypted garbage from E2EE video decryption failure.
Skip frames < 64x64 to avoid sending black/noise images to the LLM.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 16:47:20 +02:00
Christian Gick
4a37f7e9ef chore: Trigger rebuild 2026-03-09 16:20:27 +02:00
Christian Gick
cb539860d9 feat(MAT-140): Bridge voice and text context + capture video from text chat
1. Text bot can now capture video frames from active call when user
   types vision-related queries ("siehst du meinen bildschirm", etc.)
2. Voice transcript injected into text bot context during active calls
3. Text messages injected into voice transcript with [typed in chat] prefix
4. Bot text replies injected back into voice transcript

This enables seamless context sharing between voice calls and text chat.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 16:20:04 +02:00
Christian Gick
c71e3871b6 chore: Trigger rebuild 2026-03-09 16:07:16 +02:00
Christian Gick
f5e08257eb fix(MAT-140): Set E2EE decryption keys for video tracks, not just audio
Video tracks (camera + screen share) were never getting E2EE keys set
via set_key() because the condition on track_subscribed only matched
audio tracks (kind==1). This caused DEC_FAILED for all video frames,
making look_at_screen return encrypted garbage or fail entirely.

Also added track source logging to distinguish camera vs screen share.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 16:06:52 +02:00
Christian Gick
3c06ededdf fix(MAT-138): Always use HTTPS links in bot responses
Add HTTPS instruction to system prompt so LLM never generates http:// links.
Fix bare matrixhost.eu/settings references to use full https:// URLs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 15:02:37 +02:00
Christian Gick
964a3f6075 feat: scheduled reminders + less aggressive article summary
Add scheduled messages/reminders system:
- New scheduled_messages table in memory-service with CRUD endpoints
- schedule_message, list_reminders, cancel_reminder tools for the bot
- Background scheduler loop (30s) sends due reminders automatically
- Supports one-time, daily, weekly, weekdays, monthly repeat patterns

Make article URL handling non-blocking:
- Show 3 options (discuss, text summary, audio) instead of forcing audio wizard
- Default to passing article context to AI if user just keeps chatting
- New AWAITING_LANGUAGE state for cleaner audio flow FSM

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 08:32:40 +02:00
Christian Gick
19abea01ca feat: Bootstrap cross-signing keys at startup to fix Element authenticity warnings
Integrates _ensure_cross_signing() into Bot.start() flow. On first run, generates
and uploads cross-signing keys, then signs the bot device. On subsequent restarts,
detects existing cross-signatures and skips. Seeds persisted for device recovery.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 08:13:33 +02:00
Christian Gick
06b876bdea chore: Trigger rebuild 2026-03-09 08:10:44 +02:00
Christian Gick
c703c3a85c chore: Trigger rebuild 2026-03-09 06:55:30 +02:00
Christian Gick
875ff74f47 chore: Trigger rebuild 2026-03-08 18:12:49 +02:00
Christian Gick
1c8d45c31b fix: harden Matrix ecosystem — pool recovery, parallel queries, voice persistence
- Memory service: asyncpg pool auto-reconnect on connection loss, IVFFlat lists 10→100
- Bot: parallel RAG/memory/chunk queries (asyncio.gather), parallel tool execution
- Bot: skip memory extraction for trivial messages (<20 chars, no personal facts)
- Bot: persist voice call transcripts as searchable conversation chunks
- RAG: JSON parse safety in AI metadata, embedding_status tracking, fetch timeouts
- Drive sync: token refresh mutex to prevent race conditions, fetch timeouts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 18:10:22 +02:00
Christian Gick
9fcdedc4b4 feat: add search_room_history tool for deep conversation search
Allows the bot to paginate back up to 500 messages in a room
to find specific content, beyond the default 10-message context window.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 17:47:51 +02:00
Christian Gick
d6dae1da8e feat: Haiku-default model routing with Sonnet escalation + Sentry observability
Route ~90% of simple chat to claude-haiku (4x cheaper), escalate to
claude-sonnet for code blocks, long messages, technical keywords,
multimodal, and explicit requests. Sentry tags track model_used,
escalation_reason, and token usage breadcrumbs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 17:25:10 +02:00
Christian Gick
c8e5cd84bf chore: Migrate CLAUDE.md to task-mcp database
Migrated 0 section(s) to task-mcp database.
Project: MAT

Part of CF-355: CLAUDE.md migration to database
2026-03-08 13:58:19 +02:00
Christian Gick
3e31e2a18c chore: update confluence-collab submodule
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 13:45:36 +02:00
Christian Gick
36c7e36456 security: enforce per-user data isolation in memory service
- Make user_id required on all request models with field validators
- Always include user_id in WHERE clause for chunk queries (prevents cross-user data leak)
- Add bearer token auth on all endpoints except /health
- Add composite index on (user_id, room_id) for conversation_chunks
- Bot: guard query_chunks with sender check, pass room_id, send auth token
- Docker: pass MEMORY_SERVICE_TOKEN to both bot and memory-service

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 13:45:15 +02:00
Christian Gick
e584ce8ce0 chore: Trigger rebuild 2026-03-08 13:44:30 +02:00
Christian Gick
efb976a27c feat: activity video track (pulsing orb) for voice sessions
- ActivityVideoPublisher renders animated orb on 160x120 canvas
- Integrated into both agent.py and voice.py
- Updates confluence-collab submodule
2026-03-06 15:58:51 +00:00
Christian Gick
947699c988 chore(MAT-108): add CLAUDE.md and update .gitignore
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 17:56:56 +02:00
Christian Gick
108144696b feat(MAT-107): memory encryption & user isolation
- Per-user Fernet encryption for fact/chunk_text/summary fields
- Postgres RLS with memory_app restricted role
- SSL for memory-db connections
- Data migration script (migrate_encrypt.py)
- DB migration (migrate_rls.sql)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 15:56:14 +00:00
Christian Gick
0d83d3177e fix: instruct LLM to trust title/summary over garbled OCR content
Scanned passport PDFs have completely garbled OCR text that makes
the LLM think they're not passports, even though the AI-generated
title and summary correctly identify them. Added explicit instruction
to trust title/summary fields.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 16:43:13 +02:00
Christian Gick
ae059749c4 fix: Reduce history to 4 messages when RAG results present
When doc_context is available, limit history to just 4 messages (2 exchanges)
to prevent stale answer patterns from overriding fresh document search results.
Without RAG results, keep 10 messages for normal conversation context.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 15:50:21 +02:00
Christian Gick
6fb8c33057 fix: Truncate AI reply to 200 chars in memory extraction to prevent doc pollution
The AI reply often contains full document content (passport details, etc.)
which the memory extraction LLM incorrectly stores as user facts. Limiting
to 200 chars avoids including document content while keeping the gist.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 15:47:23 +02:00
Christian Gick
f1529013ca fix: Limit chat history to 10 messages to prevent stale pattern override
30 messages of "only one passport" history overwhelmed fresh RAG results.
Reducing to 10 messages (5 exchanges) provides enough conversation context
without letting stale patterns dominate.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 15:45:05 +02:00
Christian Gick
b925786867 fix: Move doc_context after history to prevent history pattern override
Two changes:
1. Reorder messages: doc_context now placed RIGHT BEFORE the user message
   (after chat history), so fresh search results override historical patterns
   where the bot repeatedly said "only one passport"
2. Strengthen doc_context instructions: explicitly tell LLM that fresh search
   results override chat history, and to list ALL matching documents

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 15:42:05 +02:00
Christian Gick
aa175b8fb9 fix: Prevent memory extraction from storing document facts as user facts
The memory extraction prompt was extracting facts from RAG search results
(e.g., passport holder names) and storing them as if they were facts about
the user. Added explicit instruction to only extract facts the user directly
states about themselves.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 15:27:47 +02:00
Christian Gick
e2bac92959 fix: increase RAG search top_k from 3 to 10
With only 3 results, passport queries often miss family members since
all passport files have similar low relevance scores. Increasing to 10
ensures all related documents are included in LLM context.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 15:06:49 +02:00
Christian Gick
4ec4054db4 feat: Blinkist-style audio summary bot (MAT-74)
Add interactive article summary feature: user pastes URL → bot asks
language/duration/topics → generates audio summary via LLM + ElevenLabs
TTS → posts MP3 inline with transcript and follow-up Q&A.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 17:39:09 +02:00
Christian Gick
1000891a97 fix: Improve voice noise tolerance and focus on latest message
- Raise VAD thresholds (activation 0.65→0.75, min speech 0.4→0.6s,
  min silence 0.55→0.65s) to reduce false triggers from background noise
- Add "focus on latest message" instruction to all prompts (voice + text)
- Add "greet and wait" behavior for new conversations instead of auto-continuing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 13:30:14 +02:00
Christian Gick
90cdc7b812 chore: Trigger rebuild 2026-03-04 13:30:06 +02:00
Christian Gick
9578e0406b feat: Matrix E2EE key management + multi-user isolation
- Add rag_key_manager.py: stores encryption key in private E2EE room
- Bot loads key from Matrix on startup, injects into RAG via portal proxy
- No plaintext key on disk (removed RAG_ENCRYPTION_KEY from .env)
- Pass owner_id (matrix_user_id) to RAG search for user isolation
- Stronger format_context instructions for source link rendering

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 11:19:02 +00:00
Christian Gick
5d3a6c8c79 chore: Trigger rebuild 2026-03-02 16:30:35 +02:00
Christian Gick
df9eaa99ec feat: Support customer-VM encrypted RAG service (MAT-68)
DocumentRAG class now prefers local RAG endpoint (RAG_ENDPOINT env var)
over central portal API. When RAG_ENDPOINT is set, searches go to the
customer VM encrypted RAG service on localhost:8765. Falls back to
portal API for unmigrated customers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:17:23 +02:00
Christian Gick
d9d2c0a849 fix: add v1 API fallback for Confluence page creation
When v2 API returns 401 (scope mismatch with classic OAuth tokens),
fall back to v1 REST API which accepts classic scopes. Also provides
clear error message asking user to re-authorize if both fail.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:25:47 +02:00
Christian Gick
f3db53798d fix: change default Confluence space from AG to AI
AG space does not exist. AI Collaboration (AI) is the correct default.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:17:33 +02:00
Christian Gick
100f85e990 fix: use Confluence v2 API for page creation (v1 returns 410 Gone)
Switch from /wiki/rest/api/content to /wiki/api/v2/pages.
V2 requires space ID instead of key, so resolve via /api/v2/spaces first.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 14:13:06 +02:00
Christian Gick
b0f84670f2 fix: video track kind detection and Confluence page creation
- Video track kind is 2 (not 0) in LiveKit Python SDK — camera was never captured
- Replace broken confluence_collab.create_page import with direct REST API call

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:30:48 +02:00
Christian Gick
3c3eb196e1 refactor: Remove !ai command prefix, natural language only
- Remove all !ai command handling (help, models, set-model, search, etc)
- Remove legacy user_keys system (WildFiles API key storage)
- Remove docs connect/disconnect commands
- Bot now responds to all DM messages and @mentions naturally
- Settings managed exclusively via matrixhost.eu portal

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 12:54:37 +02:00
Christian Gick
4bed67ac7f chore: remove all WildFiles references, use documents provider
- Remove WILDFILES_BASE_URL and WILDFILES_ORG env vars
- Rename _wildfiles_org_cache to _documents_cache
- Update _has_documents() to use provider=documents
- Remove "wildfiles connect" command alias (keep "docs connect")
- Remove WILDFILES env vars from docker-compose.yml

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 12:06:01 +02:00
Christian Gick
c2d611ace8 chore: Trigger rebuild 2026-03-02 11:13:19 +02:00
Christian Gick
4d6cba1f0c feat: switch DocumentRAG to MatrixHost API, remove WildFiles dependency
DocumentRAG now calls MatrixHost /api/bot/documents/search instead of
the WildFiles API. Removes device auth flow and legacy org provisioning.
Bot authenticates via existing BOT_API_KEY pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:06:12 +02:00