Inspiration
People delegate the boring parts of shopping, but the boring part that a plain API integration can never capture is the haggle. A price is one number; a real deal is price times quantity, which freebie the seller throws in, whether shipping is waived, and which coupon stacks on top. We wanted the shopper's browser agent to work that whole space on the site the user is already looking at, and still leave the final yes/no to a human.
What it does
Agent Market is a multi-vendor storefront with 95k+ real products. Every page
registers storefront tools on document.modelContext (WebMCP): search, product
details, cart, add-ons, coupons, and a full negotiation set. A buyer's agent
opens a negotiation and haggles a multi-dimensional deal against the store's
agent over several rounds. When they settle, the page shows a Confirm dialog and
nothing is bought until the human confirms the price. The same tools work in
a WebMCP browser (ChatGPT's in-app browser, Chrome with the flag) or drive an
in-page agent loop that needs no API key from the user.
How we built it
- Frontend: Next.js 15 / React 19 / TypeScript on Vercel.
StorefrontToolsregisters every tool ondocument.modelContext;lib/agent-loop.tsis a tool-agnostic agent harness that discovers tools from the registry and runs a hand-rolled chat-completions loop. - Backend: Spring Boot (Java) on Render, Azure SQL, Flyway, Hibernate.
- One mutation path: every state change (buyer, seller, or the server-side
auto-negotiator) goes through
OffersService.applyTurn, a pure function that is the only code allowed to decide a negotiation transition. It enforces the two hard economic limits (buyer total <= budget, seller net >= floor); which freebie and how much to concede is agent judgment. - Human gate: accepting mints an HMAC confirm token; the order is placed only when the human clicks Confirm.
- Model: Google Gemini through the OpenAI-compatible endpoint, key server-side only.
Challenges we ran into
- Gemini "thinking" models and tool history. Gemini 3.x rejects a multi-turn
tool conversation unless each function call's
thought_signatureis echoed back. The OpenAI-compat shim dropped it, so turn 2 always 400'd. We now capturetool_calls[].extra_contenton the way in and replay it on the way out. - Small models stall on long tool loops. Asking a fast model to drive
search then offer then counter then counter then accept meant it derailed a
turn later every time. We collapsed the buyer's negotiation into a single
deterministic
negotiatetool: the server plays both sides of the haggle, persists every round so the transcript is real, and returns a confirm token. The agent's job is now two calls, and reaching the confirm step no longer depends on the model finishing a loop. - Optimistic concurrency vs agent reliability. A strict round guard made the agent stall forever when its round number drifted. We made the guard opt-in for proposals and mandatory only for the binding accept.
What we learned
WebMCP's value is not "expose an API"; it is that the agent operates the same surface the human sees, so the human can step in on any turn. And the moment a flow depends on an unreliable model completing N steps, move the deterministic part
What we learned
WebMCP's value is not "expose an API"; it is that the agent operates the same surface the human sees, so the human can step in on any turn. And the moment a flow depends on an unreliable model completing N steps, move the deterministic part to the server and leave the model the judgment call.
What's next
Seller-side takeover controls, agent-negotiated bundles across multiple sellers, and a browser-vs-browser two-agent mode for a fully agentic negotiation.
Log in or sign up for Devpost to join the conversation.