mirror of
https://github.com/safishamsi/graphify.git
synced 2026-08-27 08:46:43 +00:00
fix(serve): suppress the query truncation banner when no nodes were cut (#2601)
This commit is contained in:
@@ -1082,6 +1082,16 @@ def _subgraph_to_text(G: nx.Graph, nodes: set[str], edges: list[tuple], token_bu
|
||||
total_nodes = sum(1 for l in lines if l.startswith("NODE "))
|
||||
shown_nodes = output[:cut_at].count("\nNODE ") + (1 if output.startswith("NODE ") else 0)
|
||||
cut_count = total_nodes - shown_nodes
|
||||
# Nodes render before edges, so a char-budget overflow whose cut lands
|
||||
# past the last NODE line drops only trailing edges — no whole node is
|
||||
# lost. Announcing "showing N of N nodes … among the 0 cut nodes" then
|
||||
# reads as a false truncation warning that teaches an agent to distrust a
|
||||
# complete answer and burn follow-up narrowing calls for nodes that were
|
||||
# never cut (#2601). When every node is shown the answer is complete:
|
||||
# return the full output with no banner rather than silently dropping
|
||||
# edges under a misleading notice.
|
||||
if cut_count == 0:
|
||||
return output
|
||||
# Prominent notice at the TOP so a truncated answer can never be mistaken
|
||||
# for a complete one — silence used to read as absence (#BUG2). The
|
||||
# notice + end marker sit OUTSIDE char_budget by design (two bounded
|
||||
|
||||
@@ -1496,6 +1496,33 @@ def test_subgraph_to_text_no_notice_when_under_budget():
|
||||
assert "TRUNCATED" not in text and "truncated" not in text
|
||||
|
||||
|
||||
def test_subgraph_to_text_no_banner_when_only_edges_overflow():
|
||||
"""#2601: nodes render before edges, so a budget overflow that only trims
|
||||
trailing edges cuts zero whole nodes. The banner must not fire with a
|
||||
misleading "showing N of N nodes … among the 0 cut nodes" — that pushes an
|
||||
agent to distrust a complete answer and issue pointless narrowing calls."""
|
||||
import itertools
|
||||
|
||||
G = nx.Graph()
|
||||
labels = [f"n{i}" for i in range(4)]
|
||||
for lbl in labels:
|
||||
G.add_node(lbl, label=lbl, source_file="f.py", source_location="L1", community="c")
|
||||
edges = list(itertools.combinations(labels, 2))
|
||||
for u, v in edges:
|
||||
G.add_edge(u, v, relation="calls", confidence="high")
|
||||
# Budget large enough for every NODE line but not the trailing EDGE lines.
|
||||
text = _subgraph_to_text(G, set(G.nodes), edges, token_budget=60)
|
||||
node_lines = [l for l in text.splitlines() if l.startswith("NODE ")]
|
||||
edge_lines = [l for l in text.splitlines() if l.startswith("EDGE ")]
|
||||
assert len(node_lines) == len(labels), "every node must still be shown"
|
||||
assert "TRUNCATED" not in text and "truncated" not in text
|
||||
assert "cut nodes" not in text
|
||||
# A complete answer renders the whole subgraph: suppressing the banner must
|
||||
# not silently truncate the trailing edges either (a `return output[:cut_at]`
|
||||
# would drop them and still pass the assertions above).
|
||||
assert len(edge_lines) == len(edges), "all edges must survive a complete answer"
|
||||
|
||||
|
||||
def test_subgraph_to_text_order_is_deterministic():
|
||||
"""Equal-degree nodes render in a stable order regardless of set iteration."""
|
||||
G = nx.Graph()
|
||||
|
||||
Reference in New Issue
Block a user