Skip to content

feat: enrich handover notification with phone + chat link - #2

Merged
keiravoss94 merged 1 commit into
mainfrom
feat/handover-notification-link
Apr 27, 2026
Merged

keiravoss94 merged 1 commit into
mainfrom
feat/handover-notification-link

Conversation

@keiravoss94

@keiravoss94 keiravoss94 commented Apr 27, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Owner notifications for the handover flow now include a normalized customer phone number and a platform-aware clickable link, so the owner can jump straight from Telegram into the customer's chat instead of pasting an opaque @lid into WhatsApp search.

Notification template tokens

Two new tokens, alongside the existing {customer_name}, {chat_id}, {platform}, {reason}, {activated_by} (preserved):

Token WhatsApp Telegram Other
{customer_phone} canonicalised digits via gateway.whatsapp_identity (LID → phone via lid-mapping-*.json) numeric chat_id raw chat_id
{customer_link} https://wa.me/<phone> tg://user?id=<id> raw chat_id

Resolution lives in a single helper, notify.format_chat_link(platform, chat_id) -> (phone, link), used from both tools/trigger_handover.py and the /takeback path in rules/handover.py. Failure paths (canonical helper unavailable, LID with no mapping) fall back to a last-resort suffix strip — never raises.

Default template upgrade

HandoverConfig.notify_on_activate default changes from

Handover: {customer_name} in {chat_id}. Reason: {reason}

to

Handover: {customer_name} ({platform} {customer_phone})
Reason: {reason}
Chat: {customer_link}

Old templates that only reference {chat_id} still render correctly — extra format kwargs are ignored. config.example.yaml updated to match. The basketball-jersey-demo profile config (the one that surfaced the bug) is updated separately to use the multi-line variant so Telegram makes the link clickable.

Bundled bug fix: session_id vs session_key

_pre_gateway_dispatch now stashes the cached source under both the routing session_key AND the file-style session_id (e.g. 20260427_133748_e36f7ec9). Production gateway dispatch passes task_id=session_id, not session_key, which was causing trigger_handover to return no_active_chat for every real call. Bundled here because both touch the same handover dispatch path.

Test plan

  • pytest -x — 34 passed (was 22 before this branch; adds 7 helper tests, 2 token-rendering tests, and 2 session_id regression tests; existing 22 still pass)
  • hermes gateway restart -p basketball-jersey-demo — clean, gateway-policy loaded: handover=True, tool=True, no startup errors
  • Smoke (/tmp/handover_smoke.py) against the live profile with the report's actual LID 122299244130458@lid — adapter receives:
    Handover: Kong (whatsapp 60173380115)
    Reason: smoke test
    Chat: https://wa.me/60173380115
    
    LID resolved through the profile's real lid-mapping-122299244130458_reverse.json. No @lid leakage.

Files modified

  • notify.py — adds format_chat_link helper (pure, testable, never raises)
  • tools/trigger_handover.py — passes new tokens through format(...)
  • rules/handover.py — same for the /takeback exit path
  • config.py — default notify_on_activate updated; docstring example updated
  • config.example.yaml — sample template updated, placeholder docs extended
  • __init__.py — bundled session_id/session_key dual-stash fix
  • tests/test_rules.py — TestFormatChatLink, TestNotifyTokens, test_activates_via_session_id_lookup, test_pre_dispatch_hook_stashes_by_session_id

Out of scope

  • Canonicalisation logic itself untouched — reuses gateway.whatsapp_identity.canonical_whatsapp_identifier exactly as the role-resolver plugin does.
  • state.py, notify.py's send path, listen_only.py, role-resolver, kb-tools, and other profiles' configs — untouched.

Summary by CodeRabbit

  • New Features

    • Handover notifications now display customer phone numbers and clickable chat links alongside platform information in a multi-line format for improved readability and accessibility.
  • Tests

    • Expanded test coverage for handover activation, notification formatting, and link generation across multiple messaging platforms (WhatsApp, Telegram, others).

Owner notifications now include a normalized customer phone number
and a clickable platform-specific link (wa.me/<phone> for WhatsApp,
tg://user?id=<id> for Telegram, raw chat_id elsewhere). LIDs are
canonicalized via gateway.whatsapp_identity, so the previous
"Kong (122299244130458@lid)" message becomes
"Kong (whatsapp 60173380115)" with a clickable wa.me link.

Also bundles a fix for a session_id vs session_key cache lookup
mismatch that caused trigger_handover to return no_active_chat
when the runtime forwards task_id=session_id (the file-style id)
rather than the routing session_key.

Tests: 22 -> 34 passed (added helper coverage + regression tests
for the session_id lookup path).
@keiravoss94
keiravoss94 merged commit 04d2391 into main Apr 27, 2026
@keiravoss94
keiravoss94 deleted the feat/handover-notification-link branch April 27, 2026 07:29
@coderabbitai

coderabbitai Bot commented Apr 27, 2026 •

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 565eeab0-c66d-47b6-9653-0155f4ab5c7a

📥 Commits

Reviewing files that changed from the base of the PR and between be99c6e and 45868dc.

📒 Files selected for processing (7)
  • __init__.py
  • config.example.yaml
  • config.py
  • notify.py
  • rules/handover.py
  • tests/test_rules.py
  • tools/trigger_handover.py

Walkthrough

The PR enhances handover notifications by adding context caching for sessions and enriching owner-facing messages with customer contact information. It introduces utilities to format customer phone numbers and chat links across platforms (WhatsApp, Telegram, others), and updates configuration templates and test coverage accordingly.

Changes

Cohort / File(s) Summary
Session Context Caching
__init__.py
Pre-dispatch hook now caches platform/chat context under both routing session_key and per-session session_id when a session store is present. Errors during session-store lookup are suppressed to preserve control flow.
Configuration Updates
config.py, config.example.yaml
handover.notify_on_activate message template expanded from single-line format to multi-line format that includes {platform}, {customer_phone}, and {customer_link} placeholders with platform-specific resolution logic documented.
Notification Utilities
notify.py
Introduces format_chat_link(platform, chat_id) utility that generates platform-specific contact links (WhatsApp via wa.me, Telegram via tg://user?id=, others return raw ID) and a helper to normalize WhatsApp phone identifiers by stripping suffixes and device tags.
Handover Logic
rules/handover.py, tools/trigger_handover.py
Exit and activation notification handlers now enrich messages by computing customer phone and chat link via format_chat_link() and injecting these values into template formatting. Activation also includes activated_by field tracking.
Test Coverage
tests/test_rules.py
Comprehensive additions covering session pre-dispatch caching across both identifiers, format_chat_link() platform-specific behavior (WhatsApp canonicalization via gateway, Telegram numeric IDs, fallbacks), and notification template variable interpolation for new placeholders.

Sequence Diagram(s)

sequenceDiagram
    participant Dispatch as Dispatch Pipeline
    participant Hook as Pre-Dispatch Hook
    participant Active as state.active_sessions
    participant Store as session_store
    
    Dispatch->>Hook: trigger pre-dispatch
    Hook->>Hook: construct cached tuple<br/>(platform, chat_id, user_name, gateway)
    Hook->>Active: write cached to<br/>active_sessions[session_key]
    Hook->>Store: _ensure_loaded()
    Store-->>Hook: store ready (errors suppressed)
    Hook->>Store: lookup entry for session_key
    Store-->>Hook: entry with session_id (if present)
    Hook->>Active: write cached to<br/>active_sessions[session_id]
    Hook-->>Dispatch: pre-dispatch complete
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰 A caching hop through sessions spry,
Platform-aware links now fly,
Phones and chats in format grand,
Handovers hop across the land! 🌟

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/handover-notification-link

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant