Commit Graph

350 Commits

Author SHA1 Message Date
Christian Gick
ec46c37bc5 chore: Trigger rebuild 2026-03-16 10:16:07 +02:00
Christian Gick
19b72dfe07 feat(MAT-174): LLM-based result filtering for cron search jobs
Brave Search results are passed through LiteLLM (claude-haiku) when
job config includes a `criteria` field. LLM returns indices of matching
results, filtering out noise before posting to Matrix.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 10:14:01 +02:00
Christian Gick
846634738b chore: Trigger rebuild 2026-03-16 09:42:42 +02:00
Christian Gick
193c3ad329 fix(MAT-174): Python 3.11 backslash-in-fstring compat
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 09:42:24 +02:00
Christian Gick
5e2a7715a1 chore: Trigger rebuild 2026-03-16 09:34:49 +02:00
Christian Gick
4d8ea44b3d feat(MAT-174): Add cron job scheduler and executors
Cron package that syncs jobs from matrixhost portal API, schedules execution
with timezone-aware timing, and posts results to Matrix rooms. Includes
Brave Search, reminder, and browser scrape (placeholder) executors with
formatter. 31 pytest tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 09:31:19 +02:00
Christian Gick
21b8a4efb1 fix(MAT-166): robust option matching + language-aware UI for article summary
Replace brittle exact-string matching with keyword/substring classifier
that handles edge cases (punctuation, partial matches, German variants).
Detect article language and present all prompts in the users language.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 14:41:54 +02:00
Christian Gick
62cc2a92fe fix: add German keywords for audio/text summary options (MAT-166)
'Audiozusammenfassung' and 'Textzusammenfassung' now correctly trigger
the audio/text summary flows instead of falling through to regular LLM
which says it can't create audio files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 14:29:06 +02:00
Christian Gick
cdd876fe24 fix: retry video frame capture after 2s on E2EE decryption failure
When text bot captures a frame during active call and gets 8x8 garbage
(E2EE not yet decrypted), retry once after 2s to allow key propagation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 14:20:21 +02:00
Christian Gick
1a0a2ec305 fix: E2EE key re-fetch now triggers on DEC_FAILED before cooldown
The re-fetch check was placed after the 5s cooldown return, so it never
executed. Now it triggers after 3+ DEC_FAILED regardless of cooldown.
Also relaxed stale key age filter from 60s to 300s to handle key
rotation during ongoing calls.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 13:51:10 +02:00
Christian Gick
488e50e73c fix: handle Element Call same-index key rotation on screen share
Element Call rotates E2EE keys by re-sending index 0 with a new value
when screen share starts. The LiveKit frame cryptor caches derived AES
keys per index, so overwriting index 0 does not force re-derivation.

Fix: detect when index 0 value changes and map to incrementing internal
index so the frame cryptor gets a fresh key slot. Sets all accumulated
keys on late arrival so cryptor can try both during transition.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 13:43:56 +02:00
Christian Gick
3706f568b6 fix: skip stale E2EE keys and re-fetch on persistent DEC_FAILED
- Timeline key fetch now filters by sent_ts (max 60s age) to avoid
  using keys from a previous call session
- After 3+ consecutive DEC_FAILED events, automatically re-fetches
  key from timeline in case rotation happened
- Tracks DEC_FAILED count per participant, resets on OK

This should fix the issue where the bot picks up stale encryption keys
from previous calls and can't decrypt the current caller's audio.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 13:38:10 +02:00
Christian Gick
a155f39ede feat: instant "Einen Moment" filler when look_at_screen is invoked
Plays immediate spoken feedback so the user knows the bot is processing
their screen share / camera before the vision API responds.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 13:29:21 +02:00
Christian Gick
5521819358 fix: add missing time import in voice.py E2EE handler
The on_e2ee_state callback crashed with NameError on time.monotonic()
when video tracks (screen share) arrived, preventing E2EE key re-derivation
and causing the bot to miss screen-share related questions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 13:22:04 +02:00
Christian Gick
f73de35fd4 feat: scanned PDF fallback via vision for both plain and E2EE rooms (MAT-156)
Render scanned/image-based PDF pages to PNG at 200 DPI and send to AI
model as image content when text extraction returns empty.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:35:47 +02:00
Christian Gick
0c7070ebc4 fix(e2ee): remove diagnostic logging, video E2EE confirmed working (MAT-144)
Root cause: aggressive video re-keying (set_key at 0.3/0.8/2/5s intervals)
briefly cleared encryption_key between SetKey and HKDF callback, causing
DEC_FAILED oscillation. Single set_key per track subscription is sufficient.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:16:37 +02:00
Christian Gick
4ae65524ac fix(e2ee): revert to PR #904 branch, add MAT-144 diagnostics
PR #921 requires custom WebRTC build not yet available.
Added diagnostic logging: encryption_type per track, frame_cryptors count,
and DEC_FAILED re-keying cooldown (5s) to reduce log spam.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 10:12:51 +02:00
Christian Gick
f85562ed28 fix(e2ee): switch to PR #921 Rust FFI branch for native HKDF (MAT-144)
PR #904 callback-based HKDF hack only fired for the first frame cryptor
(audio), leaving video frame cryptors with PBKDF2 - DEC_FAILED oscillation.
PR #921 integrates HKDF natively at the WebRTC C++ level, applying uniformly
to all frame cryptors (audio + video).

Also removes aggressive video re-keying workaround and adds 5s cooldown
to DEC_FAILED re-keying handler to prevent tight loops.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 09:52:32 +02:00
Christian Gick
4fc268cdd7 chore: Trigger rebuild 2026-03-10 09:38:37 +02:00
Christian Gick
1118ab5060 fix(e2ee): aggressive video re-keying after track subscription (MAT-144)
Video frame cryptors may not be fully initialized when set_key() is
first called during on_track_subscribed. Audio works immediately but
video oscillates OK↔DEC_FAILED with the same key.

Add staggered re-keying at 0.3s, 0.8s, 2s, 5s after video track
subscription to ensure the key is applied after the frame cryptor
is fully ready.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 09:38:17 +02:00
Christian Gick
7e59593c3e chore: Trigger rebuild 2026-03-10 08:34:46 +02:00
Christian Gick
61531d9913 fix(voice): disable activity video animation — causing lag (MAT-149)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 08:34:09 +02:00
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