I spent three weeks sourcing 500 perfume bottles by hand. Then I built an agent to do the job. A developer built SupplyMe, an agent that automates B2B supplier sourcing for small manufacturing orders, after spending three weeks manually sourcing 500 perfume bottles. The agent uses Gemini to extract claims from supplier pages and a deterministic confidence-scoring function to rank suppliers, and it persists every step as an event so it can continue working after the user closes the tab. I wrote this post to enter the Google × Devpost All Things Agentic hackathon https://allthingsagentichackathon.devpost.com/ https://allthingsagentichackathon.devpost.com/ . The project is SupplyMe https://github.com/fillateo/SupplyMe , submitted in the Taskmaster category I wanted 500 units of a 50ml fragrance made in Indonesia, on a first-batch budget. Five hundred is a small order, and small orders are where the B2B marketplaces stop being useful to you. The factories I wanted were not listed on any of them. The ones that were listed sorted by ad spend, and every number on every profile was a form field somebody filled in once and never opened again. So I did the job by hand. Three weeks, 41 tabs, three languages. My spreadsheet had a column for minimum order quantity and nine of its rows said ? , because most factories never publish one. I sent the same eight questions to one supplier at a time and got answers to four of them. Then two suppliers listed the same major fragrance brand as a customer. I read both pages twice. They matched in every way that mattered to me: a logo, a sentence, no date, no contract, nobody else saying it. One of those companies was lying and I had no way in. A factory tells you its real minimum inside a negotiation and tells the next buyer something else. No dataset holds that number. You learn it by asking, and you learn whether it holds by finding somebody other than the factory saying it. That is two different jobs. Read what a supplier publishes. Wait days for the answer to what it does not. A search engine does the first badly and the second not at all, and a chatbot stops existing the moment you close the tab. The thing I built is called SupplyMe. You type a product into it — "500 × 50ml EDP, Indonesia, premium packaging, minimise first-batch risk" — and then you It breaks that product into the supply chain it needs, searches for real manufacturers of each part, reads what they publish, and emails them what the web could not answer. Days later, when a factory replies, it notices that the price in the email is not the price on the website, puts both numbers back to the supplier in a single follow-up, and ranks whoever survives. Because a supplier can take three days to answer, nothing in the system waits in memory for one. Every step is a persisted event, so a reply can arrive long after the process that sent the email is gone and the mission still picks up where it left off. That is the part that makes it an agent rather than a conversation: it keeps working when you are not there. The first thing I built is the part that answers my week-one question, and it contains no model at all. Gemini reads a page and extracts claims, stamping each one with where it came from. A deterministic function turns those sources into a confidence — noisy-OR with geometric decay: CORROBORATION DECAY, CONFIDENCE CEILING = 0.55, 0.97 confidence = min 1 - math.prod 1 - w i DECAY i for i in range n , CEILING The weights are the opinionated part: | Source | Weight | |---|---| | The supplier's own email | 0.90 | | The brand's own website | 0.85 | | The supplier's website | 0.75 | | A Maps listing | 0.55 | A directory listing | 0.45 | | A bare search result | 0.30 | Decay makes the second corroborating source count for less than the first and the twentieth count for close to nothing, so twenty directory listings copying one press release land under the manufacturer's own spec sheet. That 0.45 is the marketplace problem I started with, written down as a constant. One rule held the design together. Ask a model how confident it is and you get a number that moves when you rephrase the prompt. Compute it from source identity and you get one that moves when the evidence changes. Ranking follows the same rule: a weighted sum over price, minimum-order fit, capability, lead time, evidence strength and logistics, at 20/20/20/15/15/10. Tell a mission to minimise first-batch risk and weight slides off price and onto order-size fit. The agent that writes the recommendation receives a ranking it did not compute and cannot reorder — hand it that power and the scores turn into decoration. Drawing that line meant I never had to build explainability, because the explanation is the calculation. MOQ 500 fits an order of 500 . I started by wrapping everything in an LlmAgent , because that is what the framework is for and it felt like cheating not to. Then I read the traces. Six of them made one call and returned. One prompt, one schema, one response, no branching, no tool choice. The workflow had already decided what happened next; the model was filling in a shape. The seventh looked like this against a real supplier: read page https://kemasan-wangi.example.com/ search web "PT Kemasan Wangi Nusantara Indonesia 50ml glass perfume bottle MOQ" read page https://kemasan-wangi.example.com/produk/botol-parfum-50ml Nobody scripted that sequence. It landed on the homepage, could not find what it needed, searched for the phrase that would surface a product page, and went back for it. It returned moq = 500 , quoted from "Minimum order: 500 pcs per desain" , and reported price and lead time as missing — which is what later So research stayed an agent, with search web , read page and query maps , and the other six became single structured calls. A tool loop standing in for a structured call gets you a slower and less predictable structured call at roughly ten times the price. Working out where not to put an agent was the most useful hour I spent. Measured from the API's own token counts, eight suppliers researched through to a full recommendation cost $0.29 , across 98 model calls and 562,287 input tokens. Twelve suppliers costs $0.78, and that is the number I plan against. Input tokens are nearly the whole bill, because one real supplier website runs to tens of thousands of tokens and the research agent reads several per supplier. Spend tracks how many suppliers you look at. How ambitious the brief is barely moves it. One saving worth stealing: reasoning tokens bill as output, and extraction does not need them. Reading a price out of an email gains nothing from a thinking budget. Capping it took the fast tier from 1,222 output tokens per call to 405. SupplyMe still cannot tell me which one lied, and I no longer think that was the right question. It reports one claim as corroborated by the brand's own site and a trade publication, and the other as the supplier's word with nothing behind it. Those two things arrive on my screen looking different, and I can click either one through to the sentence it came from. In week one I would have taken that over an answer. MOCK=true docker compose up --build Built with Google ADK, Gemini 3.5 Flash on Vertex AI, Cloud Run, Firestore, Pub/Sub, Cloud Tasks, Cloud Scheduler, Secret Manager, Places, Gmail over SMTP and IMAP, FastAPI, Next.js and OpenTofu.