Spaces:
Running
Download engagement-research.md from IDKHowToCodeFr/vera-engine: direct link, hf CLI and curl.
- Browser
- Download file 13.3 kB
-
https://huggingface.co/spaces/IDKHowToCodeFr/vera-engine/resolve/main/engagement-research.md
- Command line
-
hf download hf://spaces/IDKHowToCodeFr/vera-engine/engagement-research.md
-
curl -L -o engagement-research.md https://huggingface.co/spaces/IDKHowToCodeFr/vera-engine/resolve/main/engagement-research.md
Vera Engagement Framework β Research: Current Merchant Data Access
Status: Research notes β companion to engagement-design.md.
Last updated: 2026-04-26
Scope: How the existing system loads merchant + customer data at conversation init and during a turn. Used to inform what the new framework must build vs. adapt.
TL;DR
Two distinct paths exist today β merchant-facing (Vera β Dr. Meera) and customer-facing (a customer asks Vera about Dr. Meera). They share infrastructure (vera-mcp + merchant-support-mcp + Redis) but compose context very differently.
Most of what the proposed MerchantContext needs already exists in scattered form (_merchant_snapshot, _behavioral_profile, _session_scenario). The genuinely new pieces are:
CategoryContext(no existing equivalent)TriggerContext(no normalized abstraction today β every cron emits ad-hoc payloads)CustomerContext.relationship(visit history aggregation doesn't exist)EngagementComposer(no shared composer β each agent has its own prompt-builder)
The aryan dependency for category and locality is the soft underbelly β every customer-info-pack call hits aryan synchronously.
Path 1 β Merchant-facing (VeraMerchantAgent)
Init (per session, instance-level)
agents/vera/merchant_agent.py:402 β __init__:
- Spawns its own
vera_mcp_client(HTTPMCPClientβVERA_MCP_SERVER_URL, defaultvera-mcp:8000). - Inherits
BaseAgent._merchant_mcp_clientβ class-level shared singleton pointing tomerchant-support-mcp(https://search5.magicpin.com/staging/mcp-server/mcp). - No merchant data is loaded at init β agent doesn't know who it's talking to yet.
Per-turn (every inbound message)
agents/vera/merchant_agent.py:2171 β handle_input(agent_input):
- Extract
merchant_idfrommetadata.context_data.merchant_id, falling back to regex on the message body (\d{7,}). - Fire 2 parallel tasks:
_detect_state(merchant_id)β GBP connection + subscription status checks._prefetch_merchant_context(merchant_id)β full snapshot + behavioral profile.
_prefetch_merchant_context β merchant_agent.py:740
Cache-first design:
- Redis check:
vera:merchant_ctx:{merchant_id}β TTL 30 min. Hit β return immediately, skip everything below. - Parallel via
asyncio.gather:vera_merchant_snapshot(vera-mcp tool)vera_get_merchant_profile(vera-mcp tool)
- If snapshot is empty: fall back to
get_aggregated_unassociated_merchant_data(merchant-support-mcp) β basic GBP health, no commercial data. Wrap it in a snapshot-shaped envelope. - Sequential enrichments:
_prefetch_product_contextβ fans out tovera_get_subscription_context,vera_get_performance_summary, and (only if DA subscribed)da_get_campaign_context. ~2KB total, embedded into snapshot._enrich_snapshot_with_pricingβ direct HTTP tohttps://vera.magicpin.com/api/v1/merchant/pricing/get?mid=...(vera-mcp's pricing path is unreachable locally). Mounted into snapshot aspricing_recommendation.
- Stuff result into Redis at the same key, TTL 30 min.
Final state: self._merchant_snapshot and self._behavioral_profile are populated. _get_system_prompt() reads from these and serializes the snapshot directly into the LLM system prompt (merchant_agent.py:996).
What vera_merchant_snapshot actually fetches
vera-mcp/src/services/merchant_snapshot.py:51 β build_merchant_snapshot():
- Resolve identity via
gbp_resolve_merchantβ getsplace_id,location_name,merchant_title. - One async fan-out of up to 13 tool calls in parallel:
| Bucket | Tools |
|---|---|
| Merchant-level (no GBP needed) | vera_get_subscription_status, vera_get_pricing_by_merchant, vera_get_merchant_pain_points, vera_get_merchant_offer, vera_get_merchant_config, vera_get_onboarding_status, vera_get_enhancement_suggestions |
| Location-level (skipped if no place_id) | gbp_get_location, gbp_get_profile_completeness, gbp_get_performance_summary, gbp_get_search_keywords, gbp_get_review_stats, gbp_list_posts |
- Composes 7 sections:
identity,profile,reputation,growth,commercial,conversation_hooks,issues.
Note:
categoryandlocalityare not first-class fields on the snapshot β they're buried insideprofile.business_info(fromgbp_get_location) and surfaced viaaryan_client.get_merchant_v2()only whenvera_get_customer_info_packis called.
Mid-conversation tool calls
The LLM gets the full toolset from MERCHANT_MCP_ALLOWED_TOOLS (declared on the agent class) merged with _vera_mcp_tools_cache. Mid-turn tool calls flow through:
self.vera_mcp_client.call_tool(name, args)β for vera-mcp tools (HTTP)BaseAgent._merchant_mcp_client.call_tool(name, args)β for merchant-support-mcp tools (HTTP)
No re-prefetch of the snapshot mid-turn. The agent relies on the prefetched snapshot + LLM-initiated lookups when it needs fresh data.
Path 2 β Customer-facing (CustomerIncomingAgent)
agents/vera/customer_incoming_agent.py:91 β different agent, different state model.
Init + per-turn
The instance carries:
_merchant_idβ the merchant the customer is asking about_merchant_data,_merchant_name,_category,_offers,_jd_infoβ about the business_customer_phone,_customer_profileβ about the customer (the one chatting)_chat_history,_session_stateβ conversation continuity
Merchant data load β _load_merchant_data (customer_incoming_agent.py:221)
Single shape, no Redis cache:
- Primary call:
vera_get_customer_info_pack(merchant_id)β one MCP call returnsbusiness_info+reviews+photos+offers+metadatain one shot. The aggregated customer-facing endpoint. - Fallback chain if
info_packis empty:get_unassociated_merchant_dataβ basic merchant infovera_list_merchant_offersβ separate offer list
- Supplementary (non-blocking):
vera_get_merchant_jd_infoβ JustDial crawl data for additional name / address / phone.
Caching is at the request level (in-memory on the agent instance) β re-using the same merchant_id in a session avoids re-fetching.
What vera_get_customer_info_pack does
vera-mcp/src/tools/merchant_info.py:188:
- Resolve place_id:
_resolve_place_id(merchant_id)β chain of MongoDB (gbp_status) β local JSON βaryan_client.get_mapping(). - Parallel fetch:
- GBP data via
get_or_fetch(place_id)β 24h cache in MongoDB, falls through to Google Places API _get_active_offers(merchant_id)β direct MongoDB read ofofferscollection wherestatus=active_get_merchant_metadata(merchant_id)βaryan_client.get_merchant_v2()β returnsname,category,locality
- GBP data via
- Last-resort fallback:
_fetch_embed_data(place_id)β vera REST/embedendpoint if everything else came back empty.
Customer profile (the caller)
_customer_profile is loaded separately β populated in _init_customer_data from past conversation tickets keyed off _customer_phone. There's no rich CRM behind it today; it's mostly conversation continuity (last visit, last topic).
Cross-cutting infrastructure
| Concern | Implementation |
|---|---|
| MCP transport | HTTPMCPClient (vera client) β keeps a session, calls /mcp/tools/{name} HTTP POST |
| Auth | Not required for challenge bot endpoints |
| Cache key for merchant context | vera:merchant_ctx:{merchant_id} β Redis, TTL 30 min, written by _prefetch_merchant_context |
| Cache key for GBP data | gbp_health_report:{place_id} β MongoDB, TTL 24h, in vera-mcp |
| Snapshot freshness for sends | Whatever's in Redis β not refreshed on send unless agent is in active conversation |
Source of truth for category |
aryan get_merchant_v2 API (via aryan_client) β used in _get_merchant_metadata |
Source of truth for name |
aryan first, GBP business_info second |
Observations relevant to the engagement framework
What already exists
- Most of
MerchantContextalready exists β spread across_merchant_snapshot,_behavioral_profile,_session_scenario,_jd_info. AMerchantContext.from_existing(agent_state)adapter could load ~80% of the fields without any new fetching. - The customer agent already has half a
CustomerContextβ_customer_phone+_customer_profilegive us identity + conversation continuity. Missing: visit history, services received, lapse state. - Two MCP servers, one orchestration β vera-mcp (instance-level) for vera tools, merchant-support-mcp (class-level shared) for fallback merchant tools. The composer can just consume whatever
MerchantContextalready collected β no new MCP wiring required. - Cache TTL of 30 min is fine for engagement nudges that fire daily/weekly. Redis hits during conversation are plenty fresh for composition.
What does NOT exist
- No
CategoryContext. Category is just a string buried in metadata. Voice rules, peer benchmarks, knowledge digests β none of it exists. Biggest greenfield area, but also the most leveraged (one CategoryContext serves all merchants in the vertical). - No
customer_aggregatefield on the merchant snapshot. No pipeline today aggregates per-merchant customer roster stats (active count, lapsed count, retention rate). - No
TriggerContextabstraction. Every nudge type today has its own cron + its own fetch logic + its own send code. The proposedTriggerContextis the genuinely new architectural primitive; everything else is reorganization. - No visit-history aggregation per (merchant, customer_phone). Required for
CustomerContext.relationship. BOTOPS chat history has the raw data; no derived view exists. - No shared composer. Each agent has its own prompt builder embedded in
_get_system_prompt(). The proposedEngagementComposeris net new.
Operational risks to mitigate
- Aryan is the synchronous bottleneck.
aryan_client.get_merchant_v2()is the only path to category and locality, and it's a remote HTTP call. If aryan is slow, every customer-info-pack call is slow. Worth caching aryan responses per merchant for ~24h before scaling engagement frequency. - The 30-min Redis cache is keyed per-merchant β fine for in-conversation reuse, but a daily engagement cron will miss this cache 100% of the time and pay the full snapshot-build cost per send. Consider a longer-TTL background-warmed cache for the engagement loop specifically.
- No version tracking on prompts today. Every send loses the prompt-version provenance. The composer should record prompt version + context hash on every send so we can replay and A/B.
Concrete recommendation for Phase 1 of the framework
Phase 1 is mostly an adapter layer, not new infrastructure:
| Layer | Effort | What it actually does |
|---|---|---|
CategoryContext |
Net new | Build for dentistry first (offer catalog, voice, peer stats, weekly digest, patient-content seed) |
MerchantContext |
Adapter | Wrap existing _merchant_snapshot + _behavioral_profile + a new _customer_aggregate derived from BOTOPS chat history |
TriggerContext |
Net new abstraction | Normalize the payloads existing crons emit into a single shape; new triggers (research_digest, recall_due) emit it natively |
CustomerContext |
Partial adapter | Wrap existing _customer_profile, plus a new visit-history aggregator |
EngagementComposer |
Net new | Single LLM-prompted module with versioned prompt; consumes the above |
Phase 1 should NOT require modifying any existing agent. The adapter reads from existing state; the composer is a new module that runs in parallel; the new triggers (research digest, recall) are new crons that don't touch the existing matrix-followup or campaign-engagement loops.
Appendix: file pointers for follow-up implementation
agents/vera/merchant_agent.py:402β VeraMerchantAgent initagents/vera/merchant_agent.py:740β_prefetch_merchant_context(the main load)agents/vera/merchant_agent.py:899β_prefetch_product_context(subscription + DA campaign + perf summary)agents/vera/merchant_agent.py:996β system-prompt builder reads_merchant_snapshotagents/vera/merchant_agent.py:2171βhandle_inputper-turn entryagents/vera/customer_incoming_agent.py:91β CustomerIncomingAgent classagents/vera/customer_incoming_agent.py:221β_load_merchant_data(single info-pack call + fallbacks)agents/base_agent.py:80-82β MERCHANT_MCP_SERVER_URL configagents/base_agent.py:237-244β class-level shared_merchant_mcp_clientvera-mcp/src/tools/merchant_snapshot.pyβvera_merchant_snapshottoolvera-mcp/src/services/merchant_snapshot.py:51βbuild_merchant_snapshot(the 13-call fan-out)vera-mcp/src/tools/merchant_info.py:188βvera_get_customer_info_packtoolvera-mcp/src/tools/merchant_info.py:30β_resolve_place_idchain (MongoDB β JSON β aryan)vera-mcp/src/services/aryan_client.pyβ aryan HTTP client (get_merchant_v2,get_mapping)