The graph answers with paths, neighbours and a timeline - #565
Open
WaylandYang wants to merge 7 commits into
Open
The graph answers with paths, neighbours and a timeline#565WaylandYang wants to merge 7 commits into
WaylandYang wants to merge 7 commits into
Conversation
Contributor
Author
|
Two more commits put vectors where the runs said they belong, and one small lookup change:
Third DeepSeek pass on the same twelve questions: relation from |
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: WaylandYang <wayland0916@gmail.com>
WaylandYang
force-pushed
the
feat/graph-query
branch
from
September 9, 2026 14:32
35dfa72 to
1798b93
Compare
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 #558.
What changed
The model's graph tools were a name lookup and a fact dump. Now the query work happens on the server:
paths_between(from, to, max_hops ≤ 3, at?, as_of?)(utopia-store::paths): the chains of facts joining two entities, shortest first, at most ten, deduplicated (the same edge is often two facts, one dated and one not). The search meets in the middle (a's two hops against b's one), never expands a hub past the first hop, and runs both clocks: withatevery edge on a path must hold at that moment, withas_ofthe edges and the entity ownership are read as the base held them then.neighbors(entity, predicate?, object_type?, at?): one hop, grouped by predicate, each neighbour with its type and range.timeline(entity, since?, until?, predicate?): the entity's facts that state a world-time position, in order; undated facts are counted and left out.entity_factstakespredicate,object_type,since/untilandlimit, and its output is grouped by predicate with a header that says how much was cut and where to narrow. A filter that matches nothing lists the predicates the entity does have; the model's guess ("board member") and the base's word (comprised) rarely coincide (One relation arrives under several predicates #560).find_entitiesranks typed before untyped, exact before partial, heavy before light; untyped phrase entities are left out when anything typed matches (A descriptive phrase becomes an entity #559); the reply names the best match when one dominates.find_entitiesround and the "which OpenAI?" that usually followed it.undated(it readattested 2026-09-06T12:23:58.175078Z, and Qwen quoted that as the date something happened); one the text says is over readsended, date unknown.Chat.tsx).As the model sees it
paths_between("OpenAI", "Anthropic"):timeline("OpenAI"), 3.7 KB whereentity_factswas 26 KB:entity_facts(OpenAI, predicate="founder", object_type="Person"):neighbors(Anthropic, object_type="Person"):neighbors(OpenAI's board, predicate="member"), the miss that now explains itself:End to end
The twelve fresh data questions from #558 (relation ×6 in two phrasings, timeline ×3, board ×3), same scratch base, run on the rig loop of #548 merged locally with this branch. "Before" is the same harness on the same loop and prompt without these tools.
paths_betweeneach; the other 2 wereno_evidence_neededbefore any tool (the loop's gate, not the tools)timelinepaths_betweenfind_entities, reads "Best match", and still asks which OpenAIEvery turn finished with
done;steps,sourcesandtool_exchangeare stored as before; MCP lists eleven tools.The board question stays open, and the run says why: the four
comprisedfacts on "OpenAI's board of directors" carry no date, soentity_facts(…, at: "2023")correctly excludes them, and the model turns to text search. That is extraction, #559's territory (the same run shows two "Sam Altman" entities, one typed Organization with 66 facts), not the query.Also visible in the raw output and left alone here: the base holds
OpenAI —founded→ Anthropic, which is false and ranks first because it is one hop; and the specificity ranking puts investor-in-both paths above the Amodei path, because Coatue has fewer facts than Daniela Amodei.Tests
a_path_joins_two_entities— shortest first and cut atmax_hops; a path holds only when every edge holds atat; a hub is not walked through; the record axis hides an edge recorded later; a second fact on the same edge does not make a second path.time_textupdated forundated/ended, date unknown;check_calland MCP untouched.Where vectors go (second commit batch)
profile_embedding, the centroid of the contexts it was extracted from. Exact-name matches stay ahead of partial ones; inside a tier, the closest profile wins. The reply says "closest to the question". MCP passes no question and keeps the fact-count order.predicatefilter matches no fact by substring, the word is embedded and compared withrelation_types.embedding; keys within cosine distance 0.45 stand in for it, and the reply says so:predicate "member" read as has_member, member, member_of, members. Measured distances for "member":has_member0.27,members0.32,member_of0.38. Relations minted by auto-extension carry no embedding (comprisedamong them, One relation arrives under several predicates #560), so the miss that started this still ends with the predicate list rather than the alignment; the model then asks forcomprisedand gets the four board members from the graph.neighborsandtimelineacceptentity_idas well asentity; the models pass both.Third pass on DeepSeek after these: the relation question came from
paths_between6 of 6 times; timelines 3 of 3; the board question answered correctly from the graph once the model followed the predicate list (entity_facts(predicate="comprised")), from text search otherwise.Not here
neighborsis one hop by design; the model takes further hops itself.🤖 Generated with Claude Code