DEV Community

BuyWhere
BuyWhere

Posted on

Build a Singapore Price-Watch Agent with LangGraph and BuyWhere

Build a Singapore Price-Watch Agent with LangGraph and BuyWhere

In this tutorial, we'll build a simple price-watch agent using LangGraph and BuyWhere's Singapore product catalog API. The agent will monitor product prices and alert when a price drops below a threshold.

Prerequisites

  • Python 3.11+
  • LangGraph (pip install langgraph langchain-openai)
  • BuyWhere API key (free at buywhere.ai/developers)
  • OpenAI API key

What We're Building

A LangGraph agent that:

  1. Takes a product query and target price
  2. Searches BuyWhere for current Singapore prices
  3. Reports whether the target price is achievable
  4. Loops until the price is found or max retries reached

Step 1: Set Up BuyWhere Tool

import requests
from langchain_core.tools import tool

BUYWHERE_KEY = "your_key_here"

@tool
def search_singapore_prices(query: str) -> dict:
    """Search for current product prices in Singapore. Returns a list of products with prices."""
    response = requests.get(
        "https://api.buywhere.ai/search",
        params={"q": query, "sort": "price_asc", "limit": 10},
        headers={"Authorization": f"Bearer {BUYWHERE_KEY}"}
    )
    data = response.json()
    products = data.get("products", [])

    return {
        "query": query,
        "lowest_price": products[0]["price"] if products else None,
        "currency": "SGD",
        "products": [
            {
                "name": p["name"],
                "price": p["price"],
                "retailer": p["retailer"]
            }
            for p in products[:5]
        ]
    }
Enter fullscreen mode Exit fullscreen mode

Step 2: Define Agent State

from typing import TypedDict, Annotated
from langgraph.graph.message import add_messages

class PriceWatchState(TypedDict):
    messages: Annotated[list, add_messages]
    product_query: str
    target_price: float
    current_lowest_price: float | None
    price_found: bool
    attempts: int
Enter fullscreen mode Exit fullscreen mode

Step 3: Build the Graph

from langgraph.graph import StateGraph, END
from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage, HumanMessage

llm = ChatOpenAI(model="gpt-4o-mini").bind_tools([search_singapore_prices])

def search_node(state: PriceWatchState) -> PriceWatchState:
    """Search for current prices."""
    messages = state["messages"]
    response = llm.invoke(messages)
    return {"messages": [response], "attempts": state["attempts"] + 1}

def process_results(state: PriceWatchState) -> PriceWatchState:
    """Process search results and check against target."""
    # Extract tool results from messages
    last_message = state["messages"][-1]

    if hasattr(last_message, 'tool_calls') and last_message.tool_calls:
        # Tool was called, results will come back
        return state

    # Extract price from response
    content = last_message.content
    current_price = state.get("current_lowest_price")
    target = state["target_price"]

    price_found = current_price is not None and current_price <= target
    return {"price_found": price_found}

def should_continue(state: PriceWatchState) -> str:
    if state.get("price_found"):
        return "done"
    if state.get("attempts", 0) >= 3:
        return "done"
    return "search"

# Build graph
graph_builder = StateGraph(PriceWatchState)
graph_builder.add_node("search", search_node)
graph_builder.add_node("check", process_results)

graph_builder.set_entry_point("search")
graph_builder.add_edge("search", "check")
graph_builder.add_conditional_edges("check", should_continue, 
    {"done": END, "search": "search"})

graph = graph_builder.compile()
Enter fullscreen mode Exit fullscreen mode

Step 4: Run the Agent

def run_price_watch(product: str, target_price: float):
    initial_state = {
        "messages": [
            SystemMessage(content="You are a Singapore price monitoring agent. Search for product prices using the search tool."),
            HumanMessage(content=f"Find the cheapest '{product}' in Singapore. Target budget: S${target_price}")
        ],
        "product_query": product,
        "target_price": target_price,
        "current_lowest_price": None,
        "price_found": False,
        "attempts": 0
    }

    result = graph.invoke(initial_state)
    return result

# Example usage
result = run_price_watch("iPhone 16 256GB", 1500.0)
print(result["messages"][-1].content)
Enter fullscreen mode Exit fullscreen mode

Sample Output

Found iPhone 16 256GB in Singapore:
- iPhone 16 256GB Blue: S$1,399 at Harvey Norman
- iPhone 16 256GB Black: S$1,399 at Shopee  
- iPhone 16 256GB Natural: S$1,449 at Lazada

Good news! The current lowest price (S$1,399) is below your target of S$1,500.
Enter fullscreen mode Exit fullscreen mode

Going Further

  • Add email notifications when price drops are detected
  • Persist state with LangGraph checkpointing for daily monitoring
  • Expand to track multiple products simultaneously
  • Add price history tracking

Resources

Top comments (0)