Inspiration

Gen Z is getting through a tight economy by protecting small, social treats. Bank of America found in August 2026 that Gen Z has the lowest savings-to-spending ratio of any generation, yet spending at small coffee chains grew more than 25% year over year, and 92% said they buy a treat to get through a bad day or mark a good one. Datassential found that 77% of Gen Z has a little treat at least once a week, with boba among their favorites, and Circana found that 73% of consumers say these treats matter to their quality of life. A $6 milk tea is this generation’s lipstick effect: the purchase they keep when bigger ones are out of reach.

TeaLink was built with this in mind. A social media app centered around the little treats in life that keep you afloat. It offers a chance for social connection, enjoyment, and explainability for your choices.

TeaLink takes Cisco’s “When AI Agents Disagree” challenge at Level 2, plus two Level 3 pieces. Taste, Social, Explorer, and Budget each score every drink by their own goal, shop agents alone know what is in stock, and a Preference agent learns which goals this user cares about. The concierge selects agents by capability, then the plan changes when the world does: a sell-out is vetoed, an offline shop’s drinks are dropped, and Lantern Leaf can join mid-session and take the top spot. A near-tie asks the human instead of forcing a winner. On a held-out check, the learning team’s number-one pick was the user’s favorite 7 of 24 times, against 5 of 24 with fixed weights and 2 of 24 for the most popular drink. The same agents run over AGNTCY on NATS, or in-process if the bus is down.

What it does

TeaLink picks your next drink the way a group of friends would argue over the menu. One looks at what you usually love, one at what people with your taste are ordering, one at something you have not tried, and one at what still fits your budget. You get a top 3, with a match score and a reason, and you choose.

Every order teaches it. Rate a drink after pickup and the next round shifts toward what you actually cared about. When two drinks are too close to call, TeaLink asks you. When a shop sells out or goes offline, the list updates before you order something you cannot get.

Take the starting quiz to create your boba personality and taste profile. From there, you can customize your profile and posts and choose which stats to display and show off to your friends! See what your friends are up to, recommend them drinks, compare boba stats, and even become “besteas”🍵!

How we built it

We built TeaLink as a FastAPI gateway and a Vite app, and agreed on the API first so the frontend could run against mocks while the agents were still moving. The gateway is Python 3.12 with FastAPI, Uvicorn, and Pydantic. A concierge picks agents by capability, they propose and then score every drink on their own objective, and a resolver blends those scores with weights learned from the user’s picks. Every step streams to the browser as a Lens event over Server-Sent Events.

Match scores, weights, and rankings are computed in NumPy. LiteLLM only rewrites the wording of a rationale, and only when a model key is set. Menus, reviews, and taste profiles live in seeded JSON. Accounts live in SQLite, with the session in an httpOnly cookie. Checkout uses Stripe when a key is set, and otherwise the order is pay at pickup.

Agents run two ways, and the HTTP API stays the same. TRANSPORT=local calls them in-process. TRANSPORT=agntcy serves each agent as its own process and talks A2A over NATS through agntcy-app-sdk, falling back in-process if the bus is down. The frontend is React 19, TypeScript, Vite, Tailwind CSS 4, and React Router 7. Backend tests are pytest, and a small eval compares the learning team with fixed weights and a popularity baseline.

Challenges we ran into

Our first agents all scored drinks by taste. Taste always won, so the disagreement was only for show. Giving each agent its own goal made the pushback real. It also made the demo harder: every button had to change the top 3 in a way we could explain out loud.

Unrated drinks started at zero for the Social agent, so a shop that had just joined could never win. We now treat "nobody has rated this" as neutral. That is what lets Lantern Leaf take #1 when it comes online.

We also had to be honest about success. If a hit meant our #1 was the drink the user picked from the three we offered, we scored 63%. If a hit meant our #1 was that user's real favorite on the whole in-stock menu, the score drops to 7 of 24. Learning still beats fixed weights (5 of 24) and "most popular untried drink" (2 of 24). The smaller number is the one we will stand behind.

AGNTCY was the other hard part. Heartbeats, reset, and a broker that might be down all had to fail in a way the audience can see. The fallback is the same agent, so the recommendation does not change.

Accomplishments that we're proud of

The argument is visible. You can watch Budget push for price, Social cite a friend’s 5/5, a shop veto a sold-out drink, and the Preference agent say, in one sentence, what your last order changed.

The team adapts without a new prompt. Sell out, go offline, join mid-session, stop Budget, turn on the Critic. Each one is a real change in who speaks and what ranks first.

We kept the numbers deterministic. Match scores, weights, and vetoes are computed in code. A model never decides the ranking. That is what makes the demo repeatable and the Evidence page comparable.

And the product is the track. A boba order is a small collective-intelligence problem: competing goals, a fact only one agent knows, a failure in the middle of the session, and a moment when consensus is the wrong outcome and a person should choose.

What we learned

Disagreement has to be designed. If every agent shares an objective, a multi-agent system is a longer way to write one function.

A single recommendation hides the trade-off. A top 3, plus a rule for when to ask the human, turned the user’s order into both the product and the training signal.

Neutral is a score, not the absence of one. New shops, new drinks, and agents that have not spoken yet need a defined middle or the system quietly punishes anything new.

Evidence has to be allowed to look small. 7 of 24 is early, from three simulated people and eight rounds each. It is still the result that taught us the team was learning, because the baselines did worse on the same definition of a hit.

Splitting a hackathon by files and contracts worked. We merged all day without blocking each other, because neither of us edited the other’s tree.

What's next for tealink

The social layer should feed the argument more directly. A full taste quiz and favorite drinks from favorite shops are on the API. The screens that offer them are next, so a new user’s first round starts closer to what they actually order.

Location is the following agent. If you say where you are, a Location agent joins and argues for closer shops. If you skip it, the team stays as it is, and the scripted demo does not move.

After that: group orders, where two people’s Preference agents negotiate one run and say who gave ground, and tighter AGNTCY identity so only a shop’s own agent can veto its stock.

Built With

Share this project:

Updates

Submission history