Skip to main content

Dost Live

Dost (दोस्त — "friend") is KA26's AI layer. It started as a personal companion (capture a reminder, jot a note, talk) and has grown into the conversational entry point to the whole app: a Gemini function-calling agent that searches stores, finds service people, builds a cart, looks up your orders and prescriptions, posts community requests, and sets reminders — and renders every actionable result as a tappable card that deep-links to the exact record.

Internal naming: the route folder and DB tables are still heli/Heli (Dost is the user-facing brand). Invisible to users.

1. Dost is an agent, not a chatbot

Behind DOST_AGENT_LOOP=true, Dost runs a Gemini function-calling loop (src/lib/dost-tools/agent-loop.ts, MAX_AGENT_STEPS=10, plus a self-review pass). It has 19 tools (src/lib/dost-tools/registry.ts):

GroupTools
Discoversearch_stores, search_products, search_providers, search_requests, search_ads, find_saathi_ride
Personal dataget_orders, reorder_order, search_health, get_user_profile, get_purchase_history
Helperyoutube_search_url
Actset_reminder, add_to_cart, manage_cart, shopping_list, place_order, create_ad, create_request

Tools are general, never scenario-specific (there is no birthday_planner). Each wraps an existing KA26 capability. The agent gathers → decides → acts.

2. Two surfaces

SurfaceEndpointBehaviour
Home capture box (mobile/app/(tabs)/heli.tsx)POST /api/heli/captureA Gemini intent classifier (routeIntent). Reminders/notes/events are saved as HeliThoughts. Actionable / ecosystem queries ("show my orders", "find a plumber", "2 BHK for rent") are routed to kind:"chat" → the agent chat.
Chat screen (mobile/app/heli/chat.tsx)POST /api/heli/chat-streamSSE-streaming agent loop. Tool results stream back as DostActionCards.

The classifier guard looksLikeEcosystemQuery (src/lib/heli-gemini.ts) plus an explicit prompt rule keep live-data queries on the agent path — never the memory-RAG question path, which would otherwise answer from stale saved memories.

3. Action cards (nothing actionable is plain text)

Every tool result that represents an entity renders as a card in mobile/src/components/DostActionCard.tsx, deep-linking to the specific record:

ToolCardDeep-link
search_storesStoresthe shop
search_productsProductsthe item in its shop (/product/[id])
get_ordersOrders (status pill)/order/[id]
search_healthPrescriptions/health-records
search_providersProviders/provider/[code]
search_ads / search_requests / find_saathi_rideAds / Requests / Ridesthe listing / thread / ride
add_to_cart / manage_cart / reorder_orderLive cartthe cart

4. Persistent conversational carts v100

There is one active cart per (consumer, store) — enforced by a Postgres partial unique index (WHERE status='active', created via raw DDL because Prisma v6 can't express it). Dost appends and edits items by voice ("add two more", "remove the dal"), the cart persists across app restart, and checkout converts it to a StoreOrder. Models: DostCart + DostCartItem (snapshot price, @@unique(cartId, productId) merge). An abandoned-cart reminder fires once if items sit untouched for >12h. This unified what used to be two disconnected carts (Dost's server rows vs. the cart screen's phone-local storage).

5. Ecosystem reach v101

get_orders / reorder_order / search_health extend Dost past commerce into the user's own records. Order and prescription cards render with status and deep-links; the previously-inert ads/requests/Saathi cards became tappable.

6. Provider Profiles / Business Card v102

Every member can turn on a shareable occupation identity — the Share-my-Shop loop applied to people.

  • Set up: occupation, services, service area, a one-line pitch, bio. Flipping providerActive on mints a public code (Consumer.qrCode). Editor at mobile/app/provider-profile.tsx.
  • Discover: Dost's search_providers finds opt-in members for "I need a plumber in Gadag" → a Provider card. Area-ranked; never returns the caller; contact is not on the card.
  • View Profile (mobile/app/provider/[code].tsx): Call / WhatsApp Message / "Ask the community instead". Contact is revealed only here — "View Profile gatekeeps contact".
  • Share: /u/[code] is a public web business card with rich OG metadata (name · occupation) so a WhatsApp share renders a preview and pulls non-users into the install funnel.
  • Stats: ProfileViewEvent (deduped per visitor per day) + ProfileShareEvent give the member a "viewed N× · shared N×" signal.

Routes: GET/PATCH /api/consumer/provider-profile, GET /api/providers/[code] (public, contact-gated), POST /api/profile-share-event.

7. Reliability lessons (each found by live testing, not unit tests)

  • Routing: ecosystem queries were being answered from saved memory and confabulating (invented a "vanilla cake" order). Fixed by routing live-data queries to the agent loop via the classifier guard + prompt rule.
  • SSE chunk-boundary: verbose replies silently rendered as plain text — the streaming parser lost any done event that split across two network chunks, exactly when the card data arrives. Fixed with a buffering createSSEParser (mobile/src/lib/sse-parser.ts).
  • Card persistence: reopening a past session showed only text. HeliChatTurn.toolCalls (JSONB) now snapshots the agent's tool calls so a restored session rehydrates the same cards.

8. Schema

HeliThought (unified capture; kind discriminator), HeliMemory (LLM-extracted facts, soft TTL), HeliChatTurn (+toolCalls JSONB), HeliSession (auto-titled), HeliAbuseFlag. Dost V2 added DostUserProfile / DostPersona / DostVoiceSample / DostEmotionalAnchor with a documented 5-point voice-data isolation contract. Provider Profiles added Consumer.occupation/providerHeadline/providerActive/providerSince + ProfileShareEvent / ProfileViewEvent.

9. Status

Consumer app v102 (1.0.82). Backend revision 00521. DOST_AGENT_LOOP=true on production. Verified end-to-end on device: order/prescription/ad/provider cards render and deep-link; "I need an electrician" → provider card → View Profile → Call.