Repository navigation
Give each chat step fields the interface words in the reader's language, and let a query step carry its SQL, rows and failure - #957
Merged
Conversation
…ge, and let a query step carry its SQL, rows and failure 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.
Thank you, this is a careful cut. Reviewed the builder, the three writers, the wording module and the tests; the decision to keep the English detail for stored messages and to write status on successful steps is right, and the note on why the world moment cannot be called at is exactly the kind of thing that saves the next reader. Landing it now; #942 closes with it and #936 stays open for retry only. Thanks again.
WaylandYang
approved these changes
Sep 26, 2026
WaylandYang
left a comment
Contributor
There was a problem hiding this comment.
Maintainer review: sound, landing.
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 #942. Also does item (1) of #936, the query step. With #954 done, #936 stays open only for (2), retry.
Problem
6 sources,3 of 10 linked,40+ changes,failed,missing query.Chat.tsxshowslabel · detailas it comes. In the Chinese interface the trail stays in English, and moments appear as raw RFC 3339 stamps, e.g.12 facts at 2024-08-01T00:00:00Z, as recorded before ….query_datastep shows only the source name and the purpose. The SQL behind the number cannot be seen, and a query that failed shows the same step as one that returned rows.Change
Server
The three writers (
api/tools.rs,api/tools_graph.rs, andcheck_callinapi/chat.rs) now build every step with one small builder,tools::Step, instead of each assembling its ownjson!.Every step keeps
kind,labelanddetailunchanged, and gains these fields:statusok,failed,not_foundorinvalid. Successful steps carryoktoo, so the client can tell a new step from a stored one.count,totalmore40+ changes, the 10-path cap, a query cut at 200 rowsvalid_at,as_of,beforebeforeis given it is written instead of theas_ofderived from it.since,untilchangeswindow as asked (YYYY-MM-DD). Nountilmeans the window runs to now.hopsparam,missingsqlWhere this differs from the fields agreed in #942, and why:
valid_at, notat. Every stored step already hasat: the offset in the answer where the step happened, in UTF-16 units. Replay uses it to thread the trail back into the text. The chat loop sets it after the tool returns, so a world-timeatwould be overwritten.more,since/until,hops,param/missingandsqlare additions. Without them the client would have to parsedetailfor "40+", for the window's "now", for the hop count and for the argument name.Statuses:
failed: every read that failed. These tool results were already errors.not_found: an unknown document, an entity the graph tools cannot resolve, an unknown data source, or an unknown tool.entity_factson a name that matches nothing used to writeinvalid id. Its status is nownot_found, likeneighbors,timelineandpaths_between. Itsdetailis unchanged.invalid:check_callrefusals, and the tools' own argument checks (document_id,rule_id,since, andremember's text).query_data:run_queryis split so that the chat tool gets the rows and the truncation flag directly.run_querykeeps its signature and output, because the mapping preview uses it.sql,count(rows) andmore(cut at the 200-row cap).status: failed. A source that is not mounted isnot_found.labelis still the source name anddetailis still the purpose.Web
ChatStepgains the fields.kindgainsdocument, which the server already sent.steps.ts:stepLabelandstepDetailword a step from itskindand fields inS.ask.step.status, i.e. one stored before this change, shows itsdetailas before.valid_at) shows as a calendar date read in UTC, asfmtTimereadsvalid_from. It shows a time of day only when one was given.as_of,before) show in the reader's time zone throughlocalDateTime, as other recorded times do.changeswindow is worded fromsinceanduntil. The stored label ends in an English "now".Chat.tsx:stepLabelandstepDetail.en.tsandzh.ts.zhis typedtypeof S, so a missing entry fails the build.Docs
chat-and-mcp.md.Verification
Run in containers on a Linux host: Rust 1.98.1, Postgres 16 with pgvector, Node 20 with pnpm 10.2.1, and Playwright 1.58.2 with Chromium.
New and extended tests
mcp_tests.rseach_step_carries_the_fields_the_interface_wordsdispatches each tool against the fixture and checks its step:beforeoveras_of, noat, and an unknown name;hops, and an unknown id;since;rememberwith only NUL.Where the fixture does not fix a count, the test ties it to the stored
detail, which is unchanged.a_query_step_carries_its_sql_rows_and_failureregisters apostgresdata source pointing at the test database, then runs:SELECT 1 AS x:ok, 1 row, and the SQL back as written;failed;not_found.It deletes the source afterwards.
a_list_cut_at_its_limit_says_soalso checks the steps:moreand the window);total);moreandhops);failed_reads_do_not_become_successful_empty_resultschecksstatus: failedfor every failed read.rule_matches_keep_materialized_intervals_and_count_rowscheckscount.chat.rs:a_refused_call_names_its_parameter_for_the_interface.steps.test.ts(vitest, 29 cases):failed,not_foundandinvalid;changeswindow;The moments case pins
TZto America/New_York, where UTC and local readings differ, and checks first that the zone took effect.chat-view.test.mjs(browser) replays a stored conversation with two query steps. It checks:On dev (6f74a08) with only the new tests
This run used dev with only the new server tests, the
check_calltest and the browser test added. The vitest file imports the new module, so it was left out.each_step_carries_the_fields_the_interface_wordsstops at its first step:`status` should be "ok" in {"detail":"1 sources","kind":"search","label":"orchard"}.· revenue by month · 12 rows: 23 tests, 21 pass, 2 fail (the case and its parent).With this change
cargo fmt --all --checkpasses.cargo clippy --workspace --all-targets -- -D warningspasses.cargo test -p utopia-server api::: 181 passed.cargo test --workspacewithUTOPIA_TEST_REQUIRE_DB=1andUTOPIA_TEST_REQUIRE_PDFTOTEXT=1: 1199 passed, 0 failed, 5 ignored (the existing#[ignore]tests).cargo build --workspacepasses.pnpm install --frozen-lockfilepasses.pnpm test: 187 passed.pnpm buildpasses, including style-guard andtsc.Limits
detail. Rewording them by parsing it was not attempted; this was the second question in The step trail speaks English in the Chinese interface #942.toolstep the label is the tool's name, such aslist_rules,rule_matches, or the tool a refused call named. It stays an identifier.at: "2024") arrives as its first instant and shows as a date (2024-01-01), asdetaildid. The step does not carry the precision.query_datais unchanged. That includes a failed query not being marked as a tool error.