-
Opening scene: 44 places within 2 km. Fair pick Maison Premiere, nobody ranks it below #6.
-
After "No bars please": Observe → replan, 44 → 17 places, new fair pick Lilia (4 · 5 · 5).
-
Agent tab for the opening scene: 17 steps, 13 Qloo calls.
-
After swapping friend 2 (47 places, fair pick Five Leaves), a new friend likes "Joe's Pizza" and the agent asks which one.
-
Phone layout of the opening scene: Maison Premiere, nobody ranks it below #6 of 44.
Try it
- Open https://taste-truce.pages.dev. It opens on three friends in Williamsburg: 44 candidates, fair pick Maison Premiere.
- Type "No bars please" in the condition box and press Replan (or press the No bars please button). The step strip ends with Observe → replan, the places go from 44 → 17, and the fair pick becomes Lilia.
- Conditions stay through friend edits, so first press Reset exclusions (Reset on a phone) to return to 44 places. Then press Friends and, under "Replace friend 2 and recompute", press Hip-hop + sneakers. The fair pick moves to Five Leaves (47 places).
- In Friends, press Add friend, set the new friend's taste type to place, type "Joe's Pizza" and press Recompute ranks. The agent asks which Joe's Pizza you mean.
Inspiration
Three friends want dinner in Williamsburg. One likes Moonrise Kingdom and Miles Davis, one BTS and Supreme, one Taylor Swift and Lululemon. None of them has rated a restaurant.
Qloo gave the K-pop fan and the pop fan the same #1: Ume. The jazz fan ranked Ume #29 out of 44. A vote picks Ume 2 to 1, and the 29 never comes up. We wanted an agent that shows what each option costs each person.
What it does
The demo opens on this group, the "Williamsburg · majority / minority" scene.
- Qloo
/searchturns each taste into an entity ID. If a name doesn't match exactly one result, the agent stops and asks: a friend who likes the place "Joe's Pizza" gets each Joe's Pizza Qloo finds, one per address, with an option to skip. - For each friend,
/v2/insightsreturns dinner places within 2 km ranked by that friend's tastes, plus a popularity baseline with no taste signal. - The lists differ, so Qloo scores their union (44 places here) once per friend.
- The pick is maximin on ranks: lowest worst rank, then lowest rank sum, in fixed code that no model touches.
- The concession table shows each friend's rank for the places that matter:
| Place | Jazz fan | K-pop fan | Pop fan |
|---|---|---|---|
| Popularity #1: Five Leaves | 8 | 8 | 8 |
| Jazz fan's #1: McCarren Parkhouse | 1 | 39 | 39 |
| Majority #1 (2/3): Ume | 29 | 1 | 1 |
| Fair pick: Maison Premiere | 6 | 3 | 2 |
The majority pick costs the jazz fan 28 places. The fair pick costs the jazz fan five and the other two one or two each.
- Someone types "no bars please." The planner, an LLM, turns that into
exclude_categorieswithbar, which drops every place whose Qloo tags, name or description mark it as a bar. Qloo lists Maison Premiere as an oyster bar restaurant, so it goes too. That leaves 17 of the 44 places, and the new fair pick is Lilia at 4·5·5, while Ume would still win a vote at 10·1·1. The agent then reads what the veto did and offers one next step, which runs only if you click it.
"Somewhere quieter", "cheaper" and "search farther" work too; if fewer than five places survive, the search widens from 2 km to 3.5 km (5 km in Seongsu). In the Friends sheet, Hip-hop + sneakers replaces friend 2 with a Kendrick Lamar and Nike fan; from the opening scene the fair pick moves to Five Leaves. Conditions such as "no bars" stay on through friend edits until you remove them. An always-visible strip shows the steps and the Qloo call count as the agent works, and the Agent tab lists every tool call. Taste off shows the most popular places nearby instead, for comparison.
How this differs from a recommender
A recommender hands a group one confident #1. Taste Truce optimizes for the worst-off friend, which is why it passes over Ume, and shows every friend's rank for each option.
How we built it
What Qloo does here
- Taste in one domain, ranking in another. A friend gives us Moonrise Kingdom and Miles Davis, and
/v2/insightsreturns restaurants in Williamsburg ranked for that signal. No one has to rate a restaurant or connect an account first, so a new group can start from nothing. - The same places, ranked for each person. With
filter.results.entitieswe send one fixed list of candidate places and get it scored once per friend. Each friend's own search returns a different set of places, so a #3 on one list and a #3 on another can't be compared. - A reason for each score.
feature.explainability=truereports how much each of a friend's tastes contributed to a place's score. Hover over or tap a friend's name next to their rank to see each taste's share.
Candidates use filter.tags with operator.filter.tags=intersection, so a dinner place needs both the restaurant and dinner tags. A three-friend scene costs 13 Qloo calls from a cold cache.
The agent
The planner is qwen/qwen3.8-27b on Groq with tool_choice=required over nine tools, from exclude_categories and widen_radius to add_friend, and the same model proposes the next step after a veto. If the call fails, a local parser takes over. The planner only chooses tools and arguments from fixed lists and never sees a score.
The front end is React and TypeScript built with Vite, using shadcn/ui components on Base UI and Leaflet for the map. Responses are cached privately, and call caps keep the demo within one key's budget.
Challenges we ran into
Making ranks comparable took the most work. A call returns at most 50 results, so when the union is bigger the agent keeps the largest equal top-k per friend that fits. In the plain Williamsburg scene the union was 51 places and got trimmed to 49.
Names are ambiguous, and one silent wrong guess would skew a whole column, so the agent asks.
Accomplishments that we're proud of
- Every number on screen comes from a Qloo result and a short file of fixed rules.
- The fair pick lifts the outvoted friend from #29 to #6.
What we learned
Two Qloo requests with different signals return affinities on different scales, but a rank inside one shared pool means the same thing for every friend, so the app compares ranks.
What's next for Taste Truce
- Test it with real friend groups.
- More neighborhoods, opening hours and travel time.
Built With
- base-ui
- css
- docker
- groq
- html
- javascript
- leaflet.js
- openstreetmap
- python
- qloo
- qloo-insights-api
- qwen
- react
- shadcn-ui
- sqlite
- tailwindcss
- typescript
- vite
Log in or sign up for Devpost to join the conversation.