Repository navigation
Keep the previous answer's sources for the citation numbers a restatement repeats - #953
Merged
Merged
Conversation
…ment repeats Signed-off-by: dada-yan <BinjunYann@gmail.com>
WaylandYang
approved these changes
Sep 26, 2026
WaylandYang
left a comment
Contributor
There was a problem hiding this comment.
Option 1 from #943 with the number check that makes it safe: a turn that gathered nothing and cites only numbers the previous answer cited keeps those sources, stored with the turn so replays resolve them too. The three handler cases cover keep, a foreign number and a turn that searched; the limit you name is accepted. Merging.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #943.
Problem
When asked to shorten, translate or rephrase the previous answer, the assistant answers from the transcript without gathering anything, as the system prompt tells it to. It copies the answer's
[1]and[2]along with the words.Each turn starts with an empty
ToolSink, so the restating turn has no sources. Its marks open nothing, and the answer is labelled as citing no sources.Change
This implements option 1 from #943, with a number check.
When a turn keeps the previous answer's sources. Both of these must hold:
no_evidence_neededor no tool at all, and it has no source of its own.What it keeps. It takes the previous answer's stored sources that it cites, unchanged: the same objects with the same numbers.
sourcesframe. So the marks open the same passages, both live and after a reload.Historygainslast_sources. It is read from the same last assistant message aslast_tool_exchange. This follows the existing design: the last exchange is replayed precisely so that "translate it" or "say it shorter" has its evidence in view.recent_contextnow reads its rows into a smallFromRowstruct instead of a tuple. A seventh tuple field would have tripped clippy'stype_complexity.cited_numbersreads citations in the same shape that the page draws as marks (citeReincitations.ts):,or,;0is not a citation number.It is a small hand parser, because the workspace has no
regexdependency.Design doc:
chat-and-mcp.mdgains half a sentence.Limit
Suppose a follow-up restates an older answer, and every citation number it cites also appears in the previous answer. Then the marks open the previous answer's passages.
A stricter rule could leave marks unmapped whenever an earlier answer also cited the same number. But nearly every answer cites
[1], so that rule would also drop the common case: restating the last answer after a few exchanges.Verification
Run in containers on a Linux host (Rust 1.98.1, Postgres 16 with pgvector).
New tests in
chat_restated_tests.rsrun two turns in one conversation through the realchathandler, against a scripted endpoint:[1]; the second callsno_evidence_neededand restates with[1]. The second answer's stored sources and its lastsourcesframe are the first answer's source 1.[2], which the first answer never cited. It keeps no sources.[1]. It keeps only its own sources, so none.cited_numbers_reads_the_shapes_the_page_marks.[1][3],[4, 6]and[2,5].[ 1],[1 ],rows[0],[a1],[1,],[+1]and[].[2]inside[[2]].On
dev(b07af8f), with only tests 1–3 added:Test 4 uses the new function, so it was left out of that run.
With this change:
cargo fmt --all --checkpasses.cargo clippy --workspace --all-targets -- -D warningspasses.cargo test -p utopia-server api::: 175 passed.cargo test --workspacewithUTOPIA_TEST_REQUIRE_DB=1andUTOPIA_TEST_REQUIRE_PDFTOTEXT=1: 1190 passed, 0 failed, 5 ignored (the existing#[ignore]tests).cargo build --workspacepasses.