KevinIsInCoding Claude Sonnet 4.6 commited on
Commit
eb40daa
·
1 Parent(s): 0569d05

fix(query): rank trials by status+relevance, raise cap from 5 to 10

Browse files

Previously find_trials_for_entities() broke early on arbitrary set iteration
order, silently dropping relevant trials (AMX0114 was position 7, never seen).

- Collect all matching trial nodes before truncating
- Score each trial by number of linked query entities
- Sort: RECRUITING first, then ACTIVE_NOT_RECRUITING, then by score
- Raise max_trials default 5 → 10 (agent call updated to match)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Files changed (2) hide show
  1. agents/research_agent.py +1 -1
  2. graph/query.py +33 -20
agents/research_agent.py CHANGED
@@ -162,7 +162,7 @@ def _handle_search(
162
  # Step 4: Trial matching — prefer KG-linked trials, fall back to text match
163
  related_trials: list[dict] = []
164
  if graph and query_entities:
165
- related_trials = kg_query.find_trials_for_entities(graph, expanded_entities, max_trials=5)
166
 
167
  if not related_trials and query_entities:
168
  entities_lower = [e.lower() for e in expanded_entities]
 
162
  # Step 4: Trial matching — prefer KG-linked trials, fall back to text match
163
  related_trials: list[dict] = []
164
  if graph and query_entities:
165
+ related_trials = kg_query.find_trials_for_entities(graph, expanded_entities, max_trials=10)
166
 
167
  if not related_trials and query_entities:
168
  entities_lower = [e.lower() for e in expanded_entities]
graph/query.py CHANGED
@@ -72,12 +72,19 @@ def expand_query_entities(
72
  return display_names
73
 
74
 
 
 
 
75
  def find_trials_for_entities(
76
  G: nx.DiGraph,
77
  entity_names: list[str],
78
- max_trials: int = 5,
79
  ) -> list[dict]:
80
- """Return clinical trials linked to the given entity names."""
 
 
 
 
81
  if not G or not entity_names:
82
  return []
83
 
@@ -86,31 +93,37 @@ def find_trials_for_entities(
86
  matched = _find_node(G, name)
87
  target_nodes.update(matched)
88
 
89
- trials: list[dict] = []
90
- seen: set[str] = set()
 
91
 
92
  for node_id in target_nodes:
93
- # Trials point TO their targets, so look at predecessors
94
  for pred in G.predecessors(node_id):
95
  if not pred.startswith("trial:"):
96
  continue
97
  nct_id = G.nodes[pred].get("nct_id", "")
98
- if nct_id in seen:
99
  continue
100
- seen.add(nct_id)
101
- trials.append({
102
- "nct_id": nct_id,
103
- "title": G.nodes[pred].get("display_name", ""),
104
- "phase": G.nodes[pred].get("phase", ""),
105
- "status": G.nodes[pred].get("status", ""),
106
- "url": G.nodes[pred].get("url", ""),
107
- })
108
- if len(trials) >= max_trials:
109
- break
110
- if len(trials) >= max_trials:
111
- break
112
-
113
- return trials
 
 
 
 
 
 
114
 
115
 
116
  def get_entity_evidence(G: nx.DiGraph, canonical_id: str) -> dict:
 
72
  return display_names
73
 
74
 
75
+ _STATUS_RANK = {"RECRUITING": 0, "ACTIVE_NOT_RECRUITING": 1, "NOT_YET_RECRUITING": 2, "COMPLETED": 3}
76
+
77
+
78
  def find_trials_for_entities(
79
  G: nx.DiGraph,
80
  entity_names: list[str],
81
+ max_trials: int = 10,
82
  ) -> list[dict]:
83
+ """Return clinical trials linked to the given entity names.
84
+
85
+ Collects all matches, scores by number of linked entities, sorts by
86
+ status (RECRUITING first) then score, and returns the top max_trials.
87
+ """
88
  if not G or not entity_names:
89
  return []
90
 
 
93
  matched = _find_node(G, name)
94
  target_nodes.update(matched)
95
 
96
+ # score[nct_id] = number of query entities this trial links to
97
+ scores: dict[str, int] = {}
98
+ meta: dict[str, dict] = {}
99
 
100
  for node_id in target_nodes:
 
101
  for pred in G.predecessors(node_id):
102
  if not pred.startswith("trial:"):
103
  continue
104
  nct_id = G.nodes[pred].get("nct_id", "")
105
+ if not nct_id:
106
  continue
107
+ scores[nct_id] = scores.get(nct_id, 0) + 1
108
+ if nct_id not in meta:
109
+ status = G.nodes[pred].get("status", "")
110
+ meta[nct_id] = {
111
+ "nct_id": nct_id,
112
+ "title": G.nodes[pred].get("display_name", ""),
113
+ "phase": G.nodes[pred].get("phase", ""),
114
+ "status": status,
115
+ "url": G.nodes[pred].get("url", ""),
116
+ "_status_rank": _STATUS_RANK.get(status, 9),
117
+ }
118
+
119
+ ranked = sorted(
120
+ meta.values(),
121
+ key=lambda t: (t["_status_rank"], -scores[t["nct_id"]]),
122
+ )
123
+ for t in ranked:
124
+ del t["_status_rank"]
125
+
126
+ return ranked[:max_trials]
127
 
128
 
129
  def get_entity_evidence(G: nx.DiGraph, canonical_id: str) -> dict: