Skip to content

Say when an answer came from memory; answer greetings, typos and German normally - #35

Draft
devbadya wants to merge 3 commits into
cursor/compare-several-sources-in-web-search-ab70from
cursor/mark-unsourced-answers-ab70
Draft

Say when an answer came from memory; answer greetings, typos and German normally#35
devbadya wants to merge 3 commits into
cursor/compare-several-sources-in-web-search-ab70from
cursor/mark-unsourced-answers-ab70

Conversation

@devbadya

@devbadya devbadya commented Aug 26, 2026

Copy link
Copy Markdown
Owner

Stacked on #34; review that one first.

Four reported failures, one cause in common: the app reached for a tool where it had no business doing so, or failed to reach for one where it did — and either way presented the result as though it had been researched.

1. A greeting was answered with a web search

Typed on its own, hallo produced a search for HALLO - German greetings for AI assistants and a reply citing a Facebook video and a Reddit thread about how to say hello in German.

A greeting is one word, so isFollowUp read it as a fragment continuing the previous turn — which had been a research question. research-question carried over, the tool list was narrowed to web_search and read_page, and every resident exemplar ends in Source: https://…. Searching was the only thing left to do, and citing was the shape it had been shown.

BEFORE  hallo                    skill=research-question  offered=[web_search, read_page]
        Hallo, was ist Stripe?   skill=nothing            offered=[all six tools]
AFTER   hallo                    skill=small-talk         offered=[no tools at all]
        Hallo, was ist Stripe?   skill=lookup-term        offered=[web_search, read_page]

An opener now drops whatever was resident, as thanks does. small-talk claims those messages with tools: [] — no tools at all, so the template renders no tool block and there is no call format to imitate. That needs the distinction between declaring nothing (no restriction) and declaring none, which is what makes "answer this without a search" expressible.

Anchored triggers turned up a second gap: every shape lookup-term matches is anchored to the start of the message, which a greeting had taken, so Hallo, was ist Stripe? reached no skill either. Routing tries the message as written first, then with a leading greeting removed. Order matters — the other way round, a bare hallo would stop reaching small talk.

2. A misspelled name, and the language of the answer

Both of these turned out to be things the search engine already does and the brief was throwing away.

It corrects spelling. eln musk returns "Elon Musk — Wikipedia" as its first hit and every source then spells the name properly, so there is no dictionary to ship. spellingFrom compares the words of the query against the words the sources use, and the brief says where they differ:

The sources spell it "Elon" (the question wrote "eln"). Answer about that, and use their spelling.

Reported, never acted on. Rewriting the query is the 1inch failure, where the model decided the term was a typo for 1 inch and searched for a unit conversion; measured against the live web, was ist 1inch produces no correction at all, because the term is in the sources verbatim. Three guards, each a false positive first: two sources must agree on the spelling; question words are excluded by name, or wer ist elon musk reports that the sources spell it "der"; and two edits need a word long enough to go wrong twice.

It localises by query language. wer ist elon musk returns de.wikipedia.org first and the English article second. So German sources arrive on their own, as long as the query is not translated first — and the answer follows its sources. That is what the new German exemplar in research-question teaches: search with the words the question used, answer in the language it was asked in.

The same live run exposed a false conflict, now fixed: a birth year, an election year and this year came back as 1971 vs 2026 vs 2024, reported as three sources contradicting each other. A biography dates several things and contradicts none of them, so past two distinct years the comparison stays quiet.

3. A fabricated answer looked exactly like a researched one

Asked about a historical figure, the app produced ages of 48, 142 and 200 years and a claim no source made.

BEFORE — main @ 8ff7d3c
  Wie alt wurde Hitler?  -> NOTHING — answers from memory
  with no tool result:   []
  after a real search:   ["missing-source"]
  correction handed to the model: The answer cites no source. End it with
    "Source: https://www.britannica.com/biography/Adolf-Hitler".

AFTER
  all five shapes route to research-question; a joke still routes nowhere
  with no tool result:   []   → labelled unsourced: true
  after a real search:   ["unsupported-figure","missing-source"]
  correction handed to the model: No source gives 142. Drop that figure, or
    replace it with one the results above state.

The before correction is the part worth pausing on: the only finding was a missing citation, so the fix appended a real encyclopedia URL to an invented number.

  • Routing was the larger half. Only wer war X reached research-question; wie alt wurde X, wann starb X, erzähl mir über X and was hat X gemacht matched nothing. They route now, in both languages. Erzähl mir einen Witz deliberately does not.
  • unsupported-figure: a figure no tool result gave and the user never mentioned. Deliberately almost nothing counts — a plain integer of three digits or more. Decimals, thousands separators and one- and two-digit numbers are skipped, because this compares against a corpus and every way a correct number can be written differently is a way to fire on a correct answer. The honest cost: a wrong age of 48 is missed. 142 is not two digits.
  • A no source label for the case every check was blind to. A label rather than a finding, because the correction round runs with tools withheld and could not fix it. "Was meant to come from a source" is read off the tool list. Searching and then not citing stays missing-source, which has a fix.
  • Reference works get one seat instead of being dropped once two other sites answer — right for nvidia revenue, wrong for who was X.

What this does not fix

A false claim with no figure and no invented URL in it — the model asserting something untrue about a person — is caught by nothing here. Checking whether a sentence follows from a source needs entailment, so it needs a second model, and intrinsic self-grading is measured to make reasoning worse. A 0.8B model cannot be made truthful; what the app can stop doing is presenting a guess as research.

The most recent report is an example: asked Wer ist elon musk, the model called no tool and wrote about a Bremen refrigeration company. Routing was already correct and the tools were already narrowed to search — it simply did not use them. The no source label marks that reply; nothing here prevents it. Whether the rate improves is a question for the ?eval harness on a machine with a GPU.

Verification

pnpm check and pnpm build pass. 1,031 tests, 90 of them new. The before/after tables come from running the real router and the real answer check against both commits in a worktree; the spelling and language behaviour was measured against the live web. New eval scenarios: no-tool-greeting, no-tool-greeting-then-question, lookup-misspelled-name, web-german-answer, web-life-dates.

The no source label's rendering is covered by a component test rather than a screenshot: this VM has no GPU adapter, so the model cannot generate a reply to photograph.

Open in Web Open in Cursor 

cursoragent and others added 2 commits August 26, 2026 10:57
Asked about a historical figure, the model produced ages of 48, 142 and 200
years and a claim no source made. Three things let that reach the screen
looking like research, and two of them are fixable.

Routing was the larger half. Only `wer war X` reached research-question, so
`wie alt wurde X`, `wann starb X`, `erzähl mir über X` and `was hat X
gemacht` matched no skill at all — nothing suggested searching and no
exemplar showed it. Those shapes route now, in both languages, and a joke
still does not.

Figures were only ever compared against the calculator. So the one finding
on "he lived to 142" was that it cited nothing, and the correction appended
a real encyclopedia URL to an invented number. They are compared against
every tool result now, and only where there is evidence to compare with.

And an answer produced with no tool call at all had nothing to check, so
every check stayed silent. A turn whose tool list was narrowed to research
tools and that fetched nothing is now labelled: answered from the model's
own memory, not from a search. A label rather than a finding, because the
correction round has no tools and could not fix it.

Reference works also stop being dropped from the brief once two other sites
answer. For history an encyclopedia is the most reliable thing the search
returned, so it gets one seat of four: never the majority, never absent.

Co-authored-by: Sebastian <devbadya@users.noreply.github.com>
Typed on its own, `hallo` was answered with a search for "HALLO - German
greetings for AI assistants" and a reply citing a Facebook video and a
Reddit thread about how to say hello.

Two faults stacked up. A greeting is one word, so `isFollowUp` read it as a
fragment continuing the turn before — and that turn had been a research
question, so `research-question` carried over, the tool list was narrowed to
search and page reads, and every resident exemplar ends in a citation.
Searching was the only thing left to do and citing was the shape it had been
shown. An opener now drops whatever was resident, exactly as `thanks` does.

`small-talk` then claims those messages with `tools: []` — no tools at all,
so the chat template renders no tool block and there is no call format to
imitate. That distinction between declaring nothing and declaring none is
what makes "answer this without a search" expressible.

Its triggers are anchored at both ends, which turned up a second gap: every
shape `lookup-term` matches is anchored to the start of the message, so
`Hallo, was ist Stripe?` reached no skill at all. The message as written is
tried first, and only then the same message with the greeting taken off, so
a bare `hallo` still reaches small talk and a greeting in front of a
question no longer swallows it.

Co-authored-by: Sebastian <devbadya@users.noreply.github.com>
@cursor cursor Bot changed the title Say when an answer came from memory rather than from a source Say when an answer came from memory, and answer a greeting normally Aug 26, 2026
Two things the search engine already does, which the brief was throwing
away.

It corrects spelling. `eln musk` returns "Elon Musk - Wikipedia" as its
first hit and every source then spells the name properly, so there is
nothing to look up and no dictionary to ship. `spellingFrom` compares the
words of the query against the words the sources use and says where they
differ. It reports rather than rewrites, because rewriting the query is the
`1inch` failure: measured live, `was ist 1inch` produces no correction,
since the term is in the sources verbatim.

Three guards, each of them a false positive first. Two sources have to agree
on a spelling. Question words are excluded by name, or `wer ist elon musk`
reports that the sources spell it "der". And two edits need a word long
enough to go wrong twice.

And it localises by query language: `wer ist elon musk` returns
de.wikipedia.org first, `who is elon musk` the English article. So German
sources come back on their own as long as the query is not translated first,
and the answer follows its sources. The German exemplar teaches exactly
that.

A live search also turned up a false conflict this fixes: a birth year, an
election year and this year were reported as "1971 vs 2026 vs 2024", three
sources contradicting each other. A biography dates several things and
contradicts none of them, so past two distinct years the comparison is quiet.

Co-authored-by: Sebastian <devbadya@users.noreply.github.com>
@cursor cursor Bot changed the title Say when an answer came from memory, and answer a greeting normally Say when an answer came from memory; answer greetings, typos and German normally Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants