from features.base_feature import BaseFeature from tools.tavily_search import TavilySearchTool _tavily = TavilySearchTool() class MarketplaceFeature(BaseFeature): async def get_context(self, preferences_a: dict, preferences_b: dict, user_a_id: int = None, user_b_id: int = None) -> str: """ Fetch real market prices via Tavily so agents negotiate around actual reference prices, not guesses. """ raw_a = preferences_a.get("raw_details", {}) raw_b = preferences_b.get("raw_details", {}) item = ( raw_a.get("item") or raw_b.get("item") or preferences_a.get("goal", "item")[:60] ) seller_min = raw_a.get("minimum_price") or raw_a.get("min_price") or raw_a.get("asking_price") or "" seller_asking = raw_a.get("asking_price") or raw_a.get("price") or "" buyer_max = raw_b.get("maximum_budget") or raw_b.get("max_budget") or raw_b.get("budget") or "" buyer_offer = raw_b.get("offer_price") or raw_b.get("price") or "" # Flip if B is selling role_a = raw_a.get("role", "") role_b = raw_b.get("role", "") if role_b == "seller": seller_min = raw_b.get("minimum_price") or raw_b.get("min_price") or "" seller_asking = raw_b.get("asking_price") or raw_b.get("price") or "" buyer_max = raw_a.get("maximum_budget") or raw_a.get("max_budget") or raw_a.get("budget") or "" buyer_offer = raw_a.get("offer_price") or raw_a.get("price") or "" market_text = "" try: query = f"{item} used price India 2026" result = await _tavily.execute(query) answer = result.get("answer", "") results = result.get("results", [])[:3] parts = [] if answer: parts.append(f"Market summary: {answer[:300]}") for r in results: title = r.get("title", "") content = r.get("content", "")[:120] if title: parts.append(f" • {title}: {content}") market_text = "\n".join(parts) except Exception as e: market_text = f"Market search unavailable ({e}). Use your knowledge of {item} pricing." lines = [ "MARKETPLACE NEGOTIATION DOMAIN RULES:", "• Seller must NOT go below their minimum price (hard constraint).", "• Buyer must NOT exceed their maximum budget (hard constraint).", "• Classic anchoring: seller starts at asking price, buyer starts with lower offer.", "• Concede in diminishing increments (e.g., ₹3K, ₹2K, ₹1K).", "• Delivery/pickup can be offered as a non-cash concession worth ₹500-1000.", "• If gap > 20% after 3 rounds, propose splitting the difference or escalate.", "• Cite the market price from the data below to justify your position.", ] if item: lines.append(f"\nItem being traded: {item}") if seller_asking: lines.append(f"Seller asking: ₹{seller_asking}") if seller_min: lines.append(f"Seller minimum (hard floor): ₹{seller_min}") if buyer_max: lines.append(f"Buyer maximum budget (hard ceiling): ₹{buyer_max}") if buyer_offer: lines.append(f"Buyer's opening offer: ₹{buyer_offer}") if market_text: lines.append(f"\nMARKET PRICE DATA (cite this):\n{market_text}") return "\n".join(lines) def format_resolution( self, resolution: dict, preferences_a: dict, preferences_b: dict ) -> str: status = resolution.get("status", "resolved") final = resolution.get("final_proposal", {}) details = final.get("details", {}) rounds = resolution.get("rounds_taken", "?") summary = resolution.get("summary", "") raw_a = preferences_a.get("raw_details", {}) raw_b = preferences_b.get("raw_details", {}) item = raw_a.get("item") or raw_b.get("item") or "Item" if status == "escalated": return ( f"⚠️ *{item} Deal — Human Decision Needed*\n\n" f"_{summary}_\n\n" f"Agents couldn't bridge the price gap in {rounds} round(s). " f"Please negotiate directly." ) agreed_price = ( details.get("agreed_price") or details.get("price") or details.get("final_price") or details.get("amount") or final.get("summary", "") ) delivery = details.get("delivery") or details.get("handover") or "" market_ref = details.get("market_price") or details.get("market_reference") or "" lines = [f"🛒 *Deal Closed!*\n"] lines.append(f"📦 *Item:* {item}") if agreed_price: lines.append(f"💰 *Agreed price:* ₹{agreed_price}") if delivery: lines.append(f"🚚 *Delivery/Handover:* {delivery}") if market_ref: lines.append(f"📊 *Market reference:* ₹{market_ref}") lines.append(f"\n⏱ Deal closed in {rounds} round(s)") if summary and summary != "Agreement reached": lines.append(f"_{summary}_") return "\n".join(lines)