Skip to content

Caller Context Injection

When a voice agent answers an inbound call, Loquent injects caller context — the contact’s name and curated memory notes — into the AI session before the greeting. This lets the agent personalize the conversation without the caller knowing context is loaded.

  1. Twilio sends a WebSocket start event with caller metadata
  2. Loquent identifies the contact via phone number lookup
  3. If use_contact_context is enabled on the agent, Loquent fetches:
    • Contact name via get_contact_name(contact_id, organization_id)
    • Memory notes via get_contact_notes_for_agent(contact_id) — filtered to area = "memory" only
  4. A ## Caller Context block is injected as a conversation item before the AI greeting

If neither name nor notes exist, the context block is skipped entirely.

The injected context follows this structure:

## Caller Context
Contact name: Sarah Johnson
(2026-03-15T10:30:00Z): Prefers morning appointments
(2026-03-28T16:45:00Z): Interested in follow-up pricing for premium plan
Use this context to personalize the conversation naturally.
If a contact name is provided, greet the caller by name and use it
throughout the conversation. Use memory notes to inform your responses
— reference relevant facts when they come up naturally, but never say
"according to my notes" or reveal that you have a file on them.
Behave as if you simply know the caller well.

The block adapts to what’s available:

Contact hasInjected content
Name + memory notesBoth sections
Name onlyName section only
Memory notes onlyNotes section only
NeitherBlock skipped — no injection

Only notes with area = "memory" are injected. Other note types are excluded:

AreaIncludedReason
memoryCurated facts about the contact
call_annotationTransient call metadata
sms_annotationTransient message metadata
ai_enrichmentSystem-generated enrichment
alertInternal alerts
generalFree-form notes not meant for agent

This filtering reduces token consumption significantly. A contact with 30+ annotations sends only the handful of memory notes that matter.

File: src/mods/contact/services/get_contact_name_service.rs

pub async fn get_contact_name(
contact_id: uuid::Uuid,
organization_id: uuid::Uuid,
) -> Result<Option<String>, AppError>

Returns the contact’s full name (first_name + last_name, trimmed) or None. Uses select_only() to fetch just the two name columns. Filters by organization_id for org-scoped security.

File: src/mods/contact/services/notes/get_contact_notes_service.rs

pub async fn get_contact_notes_for_agent(
contact_id: uuid::Uuid,
) -> Result<Vec<AgentContactNote>, AppError>

Returns memory notes ordered by created_at ascending. The ContactNoteArea::Memory filter is applied at the database query level.

Both service calls use unwrap_or_else with structured logging:

  • If get_contact_name fails → logs with contact_id, treats as None, continues with notes
  • If get_contact_notes_for_agent fails → logs with contact_id, treats as empty vec![], continues with name
  • Neither failure blocks the call — the agent proceeds with whatever context is available

The use_contact_context flag is a per-agent setting stored in the database. When disabled, the entire context injection step is skipped. No environment variables control this behavior.