AppMunchies.
Code + prompt

I made the smartest AI models debate: Messi or Ronaldo?

by AppMunchiesOfficial

AI Panel puts your question and documents in front of a panel of top AI models, lets them debate over several rounds, then tells you what they agreed on: a one-line verdict, the to-dos every model backed, and the points still contested. Runs locally with one OpenRouter key. The main idea is to counter the sycophancy that comes with individual models and get a more balanced answer. Built by AppMunchiesOfficial.

View the code ↗

Remix this

Paste this into your AI coding assistant to rebuild it your way.

Take this repo: https://github.com/ebauch/AIPanel and rebuild "I made the smartest AI models debate: Messi or Ronaldo?" for my platform. Build **AI Panel**, a local web app where a user puts a question and source
documents to a panel of AI models, the models debate it over several rounds,
and a final "takeaways" model tells the user what the panel agreed on. The
debate is the show; the agreed takeaways are the product.

## Stack

Next.js (App Router) with React and Tailwind. All model calls go to
OpenRouter's chat completions endpoint over streaming SSE; no provider SDKs.
The API key comes from `OPENROUTER_API_KEY` in `.env.local`, or from a key the
user pastes on a Settings page (stored in localStorage and sent as a request
header that the server forwards). Ship `.env.local.example`, an MIT license,
and a README.

## Inputs (left panel, scrollable, sticky)

- Context brief: a textarea for the question or situation.
- Source documents: a list of rows, each with a label, a "Upload PDF" button
  (server extracts text), an "Add URL" button (server fetches the page and
  strips it to text, with a Wikipedia fast path via its extract API, and
  rejects localhost and private IP ranges), and a textarea for pasted text.
  Documents over 150,000 characters are truncated with a visible warning.
- Debaters: a model list fetched from OpenRouter's catalog, chat models
  only, excluding free, batch, image, audio, and embedding variants. Show
  "Top models" (one flagship per provider: Anthropic, OpenAI, Google, xAI,
  picked as the newest release, tie broken by highest completion price)
  and "More models" grouped by provider. Each row shows name, id, context
  length, price per million tokens, and a "reasoning" tag. Above the list,
  a segmented control with three presets, Flagship, Balanced (about a
  quarter of the flagship price), and Budget (about a tenth), each showing
  its estimated cost; a fourth "Custom" state when the selection matches
  none. Balanced is the default. Under it, a checkbox "Debaters remember
  their own earlier responses", on by default.
- Format: debate mode (Conversation with no stances, Assigned stances,
  Randomized stances with N iterations), reasoning effort (Normal, High),
  rounds (default 3). For stance modes, editable stance rows with a label
  and instruction, defaulting to Pro, Against, and Balanced with
  topic-neutral instructions.
- Takeaways: a checkbox "Distill takeaways when the debate ends", on by
  default, and a takeaways model dropdown defaulting to the newest Claude
  Fable, then Opus, then the first debater.
- A sticky bar at the top of the panel with "Run debate", "Stop", a cost
  estimate pill, and a "Start fresh" link that resets every input except
  the model selection, confirming first if a finished debate is on screen.
- An "Examples" strip above the form with three one-click examples:
  Messi vs Ronaldo (two Wikipedia URLs), a fictional resume vs job
  description (two bundled PDFs, generated by a script, nothing real),
  and Paris vs New York (two Wikipedia URLs). Loading one fills the form
  through the same PDF and URL paths a user would use.

## Orchestration

- For each iteration, assign stances to models in order (shuffled per
  iteration in randomized mode). For each round, each model speaks in turn.
- Every turn is a fresh chat completion with no conversation history. The
  system message is two parts: (1) panel context, the model's stance
  instruction, and the brief; (2) the documents, carrying an Anthropic-style
  `cache_control` marker with a one-hour TTL. This prefix must be
  byte-identical across a model's turns so providers cache it. The user
  message holds only the task: on the opening turn, "open the debate"; on
  rebuttals, the model's own earlier responses (when memory is on), then
  the other debaters' messages since its last turn, then "respond to their
  points".
- Send `max_tokens` of about 8k and `usage: { include: true }`. Map
  reasoning effort to OpenRouter's `reasoning.effort` only for models that
  list it in supported parameters.
- Retries: transient errors get three attempts; HTTP 429 gets five attempts
  spread over about two minutes, with the countdown shown on the turn card.
  Never retry once a token has streamed. If a turn still fails on a
  transient error, mark it Skipped and continue the debate; stop only on
  errors retrying cannot fix, showing the provider's message verbatim.
- Stream events to the browser over SSE: debate start, iteration start
  with assignments, round start, turn start, reasoning tokens, content
  tokens, activity messages, turn end with usage (prompt, completion,
  cached, cache-write tokens, and cost), round end, debate end, then the
  takeaways events.

## Takeaways

After the debate, one call to the takeaways model with the brief, the
documents, the panel roster (short model names with stances), and the full
transcript. Ask for JSON only: a one-sentence verdict of at most 25 words,
a confidence of high, medium, or low, up to eight takeaways each with a
title, one or two sentences of detail, a kind of "action" or "finding",
and lists of supporter and dissenter model names, plus up to four
disagreements with per-model positions. Append the JSON schema in code
after the user-editable instructions so edits cannot break parsing.
Request `response_format: json_object` when the model supports it. Parse
leniently (strip fences, slice from the first brace to the last), and
match supporter names to the roster tolerantly, ignoring provider
prefixes, stance suffixes, and partial names. On parse failure, show the
raw text as markdown.

## Main pane

- While running: a sticky header with panel chips colored by stance (Pro
  violet, Against amber, Balanced gray), "Round 2 of 3, model X speaking",
  elapsed time, running cost and tokens with a cached percentage, and Stop.
  Below it, turn cards grouped by iteration and round, rendering markdown,
  with a collapsible "Thinking" block that is open until content starts,
  a per-turn line like "in 44.1k (38.0k cached) / out 4.2k, $0.65", and
  collapse to about eight lines once finished with "Show more".
- When takeaways arrive, the pane becomes the result and scrolls to top:
  the verdict as a calm headline with a confidence pill and a meta line
  (panel, mode, rounds, cost, time); "Agreed by the whole panel" in green
  listing takeaways every model backed, actions before findings, each with
  one vote dot per model; "Contested" in amber for the rest with a "For:
  A, B, Against: C" line; "Where they split" listing disagreements. Then a
  row with "Show debate" (expands the transcript), Export (a select for
  Transcript, Takeaways, or both, plus "Download .md", with agreed actions
  written as a markdown task list), "Regenerate takeaways", "Edit and run
  again", and "Start fresh".
- The Run button shows "Starting…", "Running…" with a spinner, and
  "Distilling…" while work is in progress.

## Cost estimate

Estimate tokens as characters divided by four. For each turn, input is the
system prefix plus the transcript so far in that iteration, output assumed
at about 1,500 tokens; on a model's repeat turns count the document tokens
at a quarter to reflect caching. Add the takeaways call. Multiply by each
model's per-token prices from the catalog.

## Settings page

An OpenRouter key field with Save and Clear, and editable prompt templates
for the system context, the opening turn with and without a stance, the
rebuttal, and the takeaways instructions, each with a reset. Store
overrides in localStorage.

## Copy

Headline: "Put it to the panel. Walk away with what they agree on." Keep
every default prompt and example topic-neutral.