Spaces:
Sleeping
Sleeping
Commit History
-
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
-
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 -
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
-
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