Spaces:
Sleeping
Sleeping
Commit History
-
README: keep the hammer on the boss node
Emoji break mermaid only as node ids, not in labels -- 🔨 goes back on the frontier node. Re-rendered through mermaid-cli to confirm. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>85c2f25 -
README: fix the mermaid diagram, and make it readable
GitHub refused to render it: the answer node used a bare emoji as its node id, which mermaid's lexer rejects. It gets a real id, and the emoji come out of the frontier and web-search labels for the same reason. The layout is reworked while it's open -- the three bidders fan out from a single "bid in parallel" node and rejoin at the auction, web search hangs off the auction as a dotted branch, and cheap models, the boss and the answer are colour-coded. Verified by rendering the exact block through mermaid-cli rather than trusting it by eye. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>a53f046 -
ui: model name as a byline, not a chip
The answering model sat in a bordered badge above every answer, which gave a piece of metadata the same weight as an alert. It becomes plain text in the same pixel face and size, with green for tier 1 and orange for the frontier still carrying the tier. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>008fd1f -
ui: breathing dot instead of the blinking block on the status line
The terminal cursor's hard step-end on/off is fine for a caret you glance at, but it runs for the whole length of a query here and reads as flicker. It becomes a small round dot that eases between full and 30% opacity on a 1.5s curve, inheriting the status line's colour, and it holds still under prefers-reduced-motion. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>62b0967 -
ui: put the blinking cursor back on the status line
It shared a line with the emoji it was sitting next to, and the icon swap took it out along with them. The cursor is what makes the status line read as live, so it comes back -- now followed by the stage icon rather than a lightning bolt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>eaf0f93 -
ui: drawn icons for pipeline stages, brain for general, hover-only tab chips
The live status line ran on emoji and dingbats -- a lightning bolt for the auction, two different magnifiers for search and verification, crossed swords for the boss fight. Those are now stroked icons from ./icons (gavel, pencil, magnifier, scales, swords, warning, cross), picked per stage rather than baked into the status string, so emoji in the transcript can only have come from a model. The error bubble's ✖ goes the same way. General swaps its sparkle for a brain, drawn wider than tall because a taller silhouette reads as a circle with a line through it at 12px. The chat and metrics tabs drop their permanent chips; the box now appears on hover and the active tab is carried by colour. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>0a2f240 -
toggles: topic icons, nudged right, contents centred
Sparkle / angle-brackets / sigma sit beside the general, coding and logic-math labels. The row moves to pl-8 so it lines up with the composer's prompt character, and leading-none fixes the pixel font's internal leading pushing each label below its icon. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>4e72a26 -
nav: icon tabs, and a roomier bid token cap
Chat and metrics tabs become a speech bubble and a bar chart -- the analytics glyph SaaS dashboards use -- keeping the orange active state and adding aria-label/title so the words aren't lost. max_bid_tokens 3500 -> 5000, since the cap only bites on the winning speculative drafts. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>ebf62dc
-
config: strip whitespace from settings, fixing the prod image search
The new /health probe caught the real cause immediately: LocalProtocolError: Illegal header value b'Bearer tvly-dev-...T17o\n' Not a bad key -- a trailing newline on the Space secret. httpx refuses to build an illegal Authorization header, so every image search failed before leaving the container, which is why a correct-looking key produced zero images on every query. str_strip_whitespace=True on the settings model fixes this for every key at once, rather than relying on secrets being pasted cleanly. Verified by starting the app with a newline-suffixed key: previously error, now {state: ok}. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>04475cf -
health: report whether image search actually works; don't eat $ as math
/health reported image_search:true for any non-empty TAVILY_API_KEY, which never validated it. That is how production looked healthy while returning zero images on every query -- the key is present in the container but the call 401s. Verified locally by simulating it: valid key -> {state: ok, detail: startup probe returned images} quoted key -> {state: error, detail: HTTP 401: Unauthorized...} no key -> {state: disabled, detail: TAVILY_API_KEY not set} A single probe runs at boot (backgrounded, so a hanging Tavily can't delay readiness) and every real search updates the same status, so the field reflects live behaviour rather than configuration. Separately: remark-math reads a pair of $ as inline-math delimiters, so "$15 million ... $85 million" rendered everything between the amounts as one stacked KaTeX expression. A $ that introduces a digit is now escaped. Real inline math from these models arrives as \(...\) or $$...$$, both already normalised before this…e4b6db2 -
citations: space before the link, and a hover preview card
The model writes the marker straight onto the preceding word, so linking it produced "Self-Defence Forcesen.wikipedia.org". A space is now inserted unless the marker already follows whitespace or an opening bracket. The annotations carry a title for each source, which was being dropped along with everything but the URL. It now rides along as the markdown link title, so no schema change was needed to get it to the client -- react-markdown hands it straight to the anchor. A custom `a` component renders it as a small rounded card above the link on hover: source title in white, host in orange, pointer-events-none so it can't swallow the click. Ordinary links (no title) render exactly as before. Where several citations share a host, the one with a title wins, since a titleless match would render a card with nothing in it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>4ec29a9 -
images: fixed height, natural width — stop cropping entirely
Any fixed width/height pair forces a choice between cropping (object-cover) and dead space (object-contain). Both were tried and both were visibly wrong. Letting width follow the image at a fixed height sidesteps it: each tile takes the photo's own aspect ratio. Verified rendering 800x450 -> 313x176, 900x900 -> 176x176, so a 16:9 press shot and a square product render side by side with neither trimmed nor padded. max-w-[22rem] stops a panorama running away with the row. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>ef1f687
-
merge web-gate-model: images, chat controls, web gate, faster web queries
Brings in: Tavily image strip on web-search answers, stop/regenerate/ inline prompt editing/copy, the Granite t=0 web-search gate, the web-grounded hedge (22.4s -> 3.9s to first token on web queries), clickable 【domain】 citations, and the UI passes.a9cd03b -
images: rounded uncropped tiles, and a fallback search query
Tiles get rounded corners (overflow-hidden so the image is clipped to them) and go back to object-cover: object-contain avoided cropping but left dead space around anything that wasn't 4:3. More importantly the strip was vanishing at random. Searching the answer's opening sentence is accurate but a long specific sentence sometimes matches no images at all. Now it falls back to the question's subject when the answer-derived query comes up empty -- 3/3 runs return images where it had been intermittent. Also disables rehype-highlight's language auto-detection. ASCII diagrams and timelines arrive untagged, so it guessed at them and coloured ordinary words as keywords ("site", "First", "395 CE"). Blocks the model explicitly tagged still highlight; untagged ones keep the frame and monospace without the paint. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>ac47f15 -
ui: darken the composer to match ChatGPT's contrast, not its hex
#303030 is ChatGPT's composer against a #212121 page -- a small lift. This page background is pure black (globals.css --background: #000000), so the same value read far brighter here than it does there. Matching the contrast instead: #1a1a1a, neutral grey, barely above the background. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>b3eb996 -
ui: icon copy buttons, orange confirmation, ChatGPT composer grey
Code blocks showed a pixel-font "COPY" label; now they use the same two-squares glyph as the answer action row. Both copy buttons and the regenerate/pencil icons now draw from components/icons.tsx rather than each file carrying its own inline paths. The copied confirmation goes from green to GAVL orange, and the composer moves to #303030 -- ChatGPT's dark composer grey, neutral rather than warm so it reads as a distinct input surface. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>4e41e65 -
web: make 【domain】 citations real links
The web plugin writes citations as a bare domain in fullwidth brackets — "Narendra Modi is the Prime Minister of India【pmindia.gov.in】" — which renders as text that looks clickable and isn't. The actual URLs were there all along, in message.annotations, and llm.py read only message.content and dropped them. Now they're collected (from the streamed deltas too) and each marker is matched to the annotation whose host it belongs to, so the link lands on the cited page rather than the site's front door. A marker with no matching annotation is left exactly as it was: linking a bare domain would be a guess, and a wrong link is worse than none. Deltas still stream the raw markers; the linked text arrives with the final answer, which is what the client renders on `done`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>cd40eba -
pipeline: give the hedge the web, instead of skipping it
Web queries felt broken next to ChatGPT, and the search was not why. Measured on "bitcoin price today": 70ms bidding starts 22391ms auction resolves <- 22.3s of nothing on screen 22392ms web search starts 25264ms first token <- search + generation: 2.9s The pipeline set run_hedge=False for any query needing search, so that a stale ungrounded draft wouldn't flash before the search. Sound, but it meant the queries with the longest wait showed nothing at all, while ordinary queries had hedge tokens covering the same gap. Now the hedge runs web-grounded instead of not running: at t=0 when the regex knows, or restarted ~500ms in when the gate says so. And a web-grounded hedge is allowed to win the auction, which also skips the redundant second draft. Same query, after: first token 22391ms -> 3864ms, total 29.8s -> 15.9s. Non-web queries are unchanged. Known rough edge: when the auction picks a model other than the hint, the web hedge is discarded and t…7f8d928 -
images: search the answer, not the question; larger uncropped tiles
"who won the world cup" returned Argentina lifting the trophy under an answer about Spain. The search was built from the question, so it found whatever is most famous for those words rather than what this particular answer says. The image lookup now runs after the answer exists and searches its opening sentence, which names the entity the question only gestures at. Verified: the same query now returns Spain celebrating as 2026 champions, even though the sentence also contains "beating Argentina". The cost is that the lookup no longer overlaps the draft, so images appear about a second after the answer finishes instead of with it. That is the right trade -- a fast irrelevant picture is worse than a slightly late correct one. Tiles go from h-28/w-40 to h-44/w-60, and object-cover to object-contain: these are photos of one specific thing, and cropping to fill was cutting the subject in half. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>b494250 -
pipeline: Granite web-search gate, racing the hedge
A tiny model (ibm-granite/granite-4.1-8b) answers "does this need a web search?" at t=0, OR'd into the existing regex and bidder signals. Motivation is recall, not speed. The regex scores 100% on its own test file but 62.5% on held-out phrasing -- it misses ordinary questions like "did the fed cut rates" and "what did apple announce". The gate model scored 100% on the same held-out set (evals/bench_web_gate.py). It runs in PARALLEL with the hedge, not before it. The gate's TTFT (~450-500ms measured) is about the same as the hedge model's, so putting it on the critical path would roughly double time-to-first-token on the majority of queries, which need no search at all. Racing instead, a "yes" cancels the hedge ~500ms in rather than at auction time (2-4s), so the user sees far less doomed text before the reset. Fails open: an outage or unparseable reply returns None, which callers treat as "no opinion", so the regex and bidder flags still decide. Cost is ~$0.000007/query, tracked as …567b94e -
evals: tunable reasoning budget, so reasoning models score fairly
gpt-5-nano emits 400-1400 reasoning tokens at default effort, so the fixed 32-token cap hit finish_reason=length before any content and scored as a hard failure. With --max-tokens 600 --effort minimal it is 100% accurate -- and 1297ms p50, which is the real reason to reject it. Also accepts non-delta stream chunks; Cohere sends a whole message at once and was scoring zero on a parsing quirk rather than on merit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>4546097 -
evals: benchmark candidate models for the t=0 web-search gate
Measures TTFT and accuracy for small models answering the one yes/no question the gate asks, and scores the incumbent regex alongside them. Two datasets, because the distinction turned out to decide the result: the regex scores 100% on tests/test_web_heuristic.py, but those tests are what it was tuned against. On held-out phrasings it gets 62.5%. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>a7b9c56 -
chat: stop, regenerate, inline prompt editing, copy answer
Extracts runQuery(query, prefix) out of send() so a query can run against a truncated conversation -- that's what lets edit and regenerate rewrite history rather than only append to it. - stop: the send button becomes a stop button mid-stream, aborting the fetch. The partial answer is discarded and the abort is not treated as an error; the prompt stays put with a retry beside it. - edit: click the pencil on your own message to edit it in place; submitting drops every turn that followed. - copy/regenerate: icon row under each answer. Regenerate only on the last one, since re-asking mid-thread would silently discard the rest. Also centers the message column at 66rem and tightens the toggle row. copyText() replaces two silent-failure clipboard paths: writeText rejects on an unfocused document and is absent on insecure origins, and neither call site had a catch, so a failed copy gave no feedback at all. Falls back to execCommand. Known gap: a stopped run's spend is not counted.…b3def84 -
images on web-search answers, via Tavily
The OpenRouter web plugin runs search server-side and returns no image data, so image-worthy queries now make one Tavily call of their own. Gated twice over: the query must already be doing a web search, and either a bidder must set the new wants_images flag or the visual-intent regex must fire. Bidders alone proved unreliable -- they disagree with each other on identical queries and miss implicit subjects like a named office-holder or a rocket launch -- so the regex backstop mirrors what _needs_web_heuristic already does for needs_web. Search queries are stripped of conversational scaffolding first: "show me photos of the new iPhone 17" was searching for the literal words "show me photos of" and returning stock art of the phrase. Fails soft everywhere: no key, a timeout, or an empty result all just mean no images, never a degraded answer. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>7c53dcc
-
rich teaching answers, math rendering fix, emoji hard cap
Backend: - Teaching-style queries ("explain in detail", "how does X work", "step by step", "go deeper") discard the bid-inline answer and run a dedicated ANSWER_SYSTEM draft: the bidding context compresses answers (1 diagram) while the same model through the draft path produces the full step-by-step multi-diagram style (9 diagrams / 8 steps measured live). - _FORMATTING: skeleton exemplar for teaching answers (numbered steps, tiny diagram per step, closing full-picture diagram); diagram guidance broadened to academic/conceptual explanations and "explain further" requests. - Math rules added to the shared formatting block (tier-1 models had none): $$-delimited environments, double-backslash rows, balanced delimiters — fixes garbled matrix/aligned output. Frontend: - Markdown: wrap bare \begin{aligned|matrix|cases|...} environments in $$ (models emit them undelimited; remark-math left them as raw text), with a stash so already-delimited math is never double-wrapped. …b45aa65 -
chat tips: friendlier copy with GAVL as the actor
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>0ea0f0b -
web-need detection at t=0, shared answer formatting, friendly copy
Backend: - t=0 regex web gate (_needs_web_heuristic): phrase-based recency signals + year>=cutoff (model_knowledge_cutoff_year=2024) + _CURRENT_STATE questions (role holders, ages, net worth) with a historical-year guard. Runs before any model (~20us) and skips the speculative hedge for web queries, so a stale "I don't know" never flashes before the search. - Bidder-caught web queries (regex missed) announce "Let me search the web for you" before searching; regex-caught ones search silently. - Second-chance fallback: if a draft admits it lacks fresh info (_admits_no_fresh_info), re-answer once with live web search (stream + non-stream paths). - Shared _FORMATTING block applied to BOTH ANSWER_SYSTEM and BID_SYSTEM's speculative ---ANSWER--- (root cause of format/emoji rules being skipped when a confident bid shipped directly): answer shape, ASCII-diagram guidance, 2-3 emojis on longer answers / none on short. - tests/test_web_heuristic.py: 58 labeled cases pinning fi…f54215b -
answer formatting + UI: rich-answer format prompt, gpt-oss labels, input polish
- ANSWER_SYSTEM: prescribe a shape for longer answers (short answer, core idea, ## sections, prose/bullets, concise takeaway) with sparse emojis; greetings/simple facts stay plain. - BidArcade + MetricsDashboard: relabel the general bidder GEMMA-4 -> GPT-OSS (splash animation + metrics label; label key now matches backend "gpt-oss"). - Chat: narrower reply bubbles, taller left-aligned input pill, one-line opening tagline, centered toggles+input cluster. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>786e829 -
fix(hf): colorTo orange -> yellow (HF Spaces only allows preset colors)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>bca8f6a -
router: GPT-OSS 120B generalist + Llama 4 Scout verifier; greeting fix; input UI
Backend: - Generalist slot (topic "general") -> openai/gpt-oss-120b: sub-300ms median TTFT and cheaper ($0.037/$0.17 vs Llama 4 Maverick's $0.20/$0.80). Paid endpoint on both id slots so the t=0 hedge stays fast; provider_sort=latency routes to the quickest provider. - Verifier -> meta-llama/llama-4-scout, a different model from the generalist so it never grades its own drafts (keeps the quality gate independent). - VERIFY_SYSTEM: add a greetings/small-talk exception so "hello" -> a friendly reply passes at 0.9+ instead of being failed for invented "demands". Frontend (Chat input): - Circular send button with a right-arrow icon (app orange palette). - Centered toggles+input cluster; taller pill; left-aligned cursor/text. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>739705b
-
user message bubbles: rounded-full to match the input pill
653eea1 -
input typed text stone-200 -> stone-100 (closer to white)
2ac9617 -
toggles up (mt-3->mt-1), bigger gap to input box (mt-2->mt-4)
b56fda3 -
nudge topic toggles right (pl-4)
72cc7da -
remove 'topic' label next to the toggle buttons
8f68851 -
input box: rounded-3xl -> rounded-full (pill), more side padding
d3774ee -
brighten input placeholder text stone-600 -> stone-400
7268ea9 -
remove borders from topic toggles and chat/metrics tabs
Toggles (general/coding/logic-math) and the chat/metrics tabs lose their outlines; active/inactive now shown by background fill only, rounded.1e5f7b1 -
remove input box border; subtle bg fill (rounded, borderless)
b9f7145 -
README: rebrand to GAVL, fancy rewrite with diagram, features, badges
6866437 -
richer /explain, new copy: splash tagline, greeting, bot animation
- /explain: longer, more detailed walkthrough (bidders, auction, learned track record, verification, escalation/boss, web search, the payoff) - splash tagline -> 'Ask more, know faster, pay less' - input greeting -> 'Hi, what's going on?' - bot animation: 'Live Auction House' -> 'The Bots Are Warming Up'; 'waiting for a query…' -> 'Let them compete — the smartest answer wins'e726173 -
tips as rotating input placeholder; boss opener holds longer; pixel tagline
- moved the /explain tips off the live model output into the input-box placeholder, rotating every 10s; index 0 is always a greeting on open - removed the in-answer tip ticker (no TTFT concern, cleaner output) - boss/search ticker holds its opener ~7s before rotating (so 'someone called the boss??' lingers), then cycles every 2.2s - chat empty-state tagline now uses the pixel title font4f10287 -
chat empty state: drop NEW GAME + box, keep only the (bigger) tagline
8bb2f6c -
tips linger ~10s into a query instead of vanishing at first token
Tips were gated on 'no answer text yet', so they disappeared the instant streaming began. Now a 10s timer (tipsOn) keeps a rotating tip visible above the streaming answer for the first ~10s of each query, then it fades. Boss/search tickers still take precedence and hide tips.6417045 -
rebrand to GAVL
- title AUCTIONROUTER_ -> GAVL_ (header, splash, browser tab) - splash tagline -> 'Ask more, pay less' - chat empty state -> 'No limits to curiosity. Ask anything.' - /explain heading -> 'How GAVL works'0e962a8 -
loading tips + /explain command
- while the auction runs (no answer text yet), a rotating tip line shows in the ticker slot — one tip points to /explain. Reuses the boss/search ticker mechanism; only shows during the plain wait (not boss/search). - typing /explain prints a prewritten, well-formatted Markdown walkthrough of the bid -> auction -> verify -> escalate -> web-search flow locally, with no pipeline call/cost. Run-less messages skip the model/cost badge.4ab7432 -
narrow answer bubbles further 68% -> 58%
c7077b2 -
needs_web: flag specific numbered/named items (e.g. LeetCode 3499)
Qwen confabulated a LeetCode problem instead of searching. needs_web guidance now also covers a specific identified item the model can't confidently recall — a numbered problem, a specific product/version/ paper/API — 'don't invent it or say it doesn't exist, look it up'. Verified: 'leetcode 3499' -> needs_web true, real problem + citation.710d24e -
answer body text stone-300 -> stone-200 (closer to white)
a0bb5db -
answer links open in a new tab (target=_blank, rel=noopener)
01fe25c