Skip to content

Commit ebc0b38

Browse files
anthonylee991claude
andcommitted
Run cargo fmt to fix formatting
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1db7ac0 commit ebc0b38

11 files changed

Lines changed: 242 additions & 134 deletions

File tree

src/benchmark/mod.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,12 @@ pub fn run_benchmark(
308308
cases: &[TestCase],
309309
verbose: bool,
310310
) -> Result<BenchmarkResult> {
311-
run_benchmark_with("GliNER", |text| extractor.extract_triplets(text), cases, verbose)
311+
run_benchmark_with(
312+
"GliNER",
313+
|text| extractor.extract_triplets(text),
314+
cases,
315+
verbose,
316+
)
312317
}
313318

314319
/// Print the benchmark summary
@@ -352,7 +357,10 @@ pub fn print_summary(result: &BenchmarkResult) {
352357
/// Print comparison between two benchmark results
353358
pub fn print_comparison(before: &BenchmarkResult, after: &BenchmarkResult) {
354359
println!("\n{}", "=".repeat(60));
355-
println!("COMPARISON: {} vs {}", before.extractor_name, after.extractor_name);
360+
println!(
361+
"COMPARISON: {} vs {}",
362+
before.extractor_name, after.extractor_name
363+
);
356364
println!("{}", "=".repeat(60));
357365

358366
let precision_delta = (after.precision - before.precision) * 100.0;

src/extractor/gliner.rs

Lines changed: 75 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,87 @@ use gliner::model::{input::text::TextInput, params::Parameters, pipeline::span::
55

66
/// Known relation verbs for extracting predicates from text between entities.
77
const RELATION_VERBS: &[&str] = &[
8-
"works", "founded", "leads", "manages", "joined", "acquired", "owns",
9-
"based", "located", "headquartered", "reports", "partnered", "uses",
10-
"built", "developed", "created", "provides", "competes", "invested",
11-
"launched", "serves", "appointed", "hired", "employs", "supervises",
12-
"sold", "purchased", "ordered", "shipped", "reviewed", "paid",
13-
"governs", "applies", "requires", "depends", "integrates", "runs",
14-
"heads", "oversees", "established", "operates", "supports", "maintains",
15-
"produces", "manufactures", "supplies", "distributes", "sponsors",
8+
"works",
9+
"founded",
10+
"leads",
11+
"manages",
12+
"joined",
13+
"acquired",
14+
"owns",
15+
"based",
16+
"located",
17+
"headquartered",
18+
"reports",
19+
"partnered",
20+
"uses",
21+
"built",
22+
"developed",
23+
"created",
24+
"provides",
25+
"competes",
26+
"invested",
27+
"launched",
28+
"serves",
29+
"appointed",
30+
"hired",
31+
"employs",
32+
"supervises",
33+
"sold",
34+
"purchased",
35+
"ordered",
36+
"shipped",
37+
"reviewed",
38+
"paid",
39+
"governs",
40+
"applies",
41+
"requires",
42+
"depends",
43+
"integrates",
44+
"runs",
45+
"heads",
46+
"oversees",
47+
"established",
48+
"operates",
49+
"supports",
50+
"maintains",
51+
"produces",
52+
"manufactures",
53+
"supplies",
54+
"distributes",
55+
"sponsors",
1656
];
1757

1858
/// Prepositions that attach to verbs to form compound predicates.
19-
const PREPOSITIONS: &[&str] = &[
20-
"at", "in", "for", "with", "to", "by", "of", "from", "on",
21-
];
59+
const PREPOSITIONS: &[&str] = &["at", "in", "for", "with", "to", "by", "of", "from", "on"];
2260

2361
/// Pronouns and noise words that should never be entities.
2462
const GARBAGE_WORDS: &[&str] = &[
25-
"our", "we", "us", "they", "my", "your", "his", "her", "i", "me",
26-
"it", "this", "that", "these", "those", "its", "their", "he", "she",
27-
"who", "which", "what", "where", "when", "how", "why",
63+
"our", "we", "us", "they", "my", "your", "his", "her", "i", "me", "it", "this", "that",
64+
"these", "those", "its", "their", "he", "she", "who", "which", "what", "where", "when", "how",
65+
"why",
2866
];
2967

3068
/// Section header words that GliNER sometimes picks up as entities.
3169
const SECTION_HEADERS: &[&str] = &[
32-
"overview", "summary", "conclusion", "introduction", "background",
33-
"features", "pricing", "security", "details", "description",
34-
"requirements", "objectives", "scope", "methodology", "results",
35-
"abstract", "appendix", "references", "contents",
70+
"overview",
71+
"summary",
72+
"conclusion",
73+
"introduction",
74+
"background",
75+
"features",
76+
"pricing",
77+
"security",
78+
"details",
79+
"description",
80+
"requirements",
81+
"objectives",
82+
"scope",
83+
"methodology",
84+
"results",
85+
"abstract",
86+
"appendix",
87+
"references",
88+
"contents",
3689
];
3790

3891
/// Check if an entity text is garbage that should be filtered out.
@@ -65,7 +118,10 @@ fn extract_verb_predicate(between_text: &str) -> String {
65118

66119
for (i, word) in words.iter().enumerate() {
67120
let lower = word.to_lowercase();
68-
if RELATION_VERBS.iter().any(|v| lower == *v || lower.ends_with(v)) {
121+
if RELATION_VERBS
122+
.iter()
123+
.any(|v| lower == *v || lower.ends_with(v))
124+
{
69125
// Check if next word is a preposition to attach
70126
if i + 1 < words.len() {
71127
let next_lower = words[i + 1].to_lowercase();

src/extractor/hybrid.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use crate::extractor::{gliner::GlinerExtractor, normalize_predicate, patterns::PatternMatcher, Triplet};
1+
use crate::extractor::{
2+
gliner::GlinerExtractor, normalize_predicate, patterns::PatternMatcher, Triplet,
3+
};
24
use anyhow::Result;
35

46
/// Hybrid extractor that combines GliNER neural extraction with pattern-based rules.
@@ -32,8 +34,7 @@ impl HybridExtractor {
3234
for gt in gliner_triplets {
3335
// Check if this triplet overlaps significantly with any pattern triplet
3436
let dominated = pattern_triplets.iter().any(|pt| {
35-
spans_overlap(pt.source_span, gt.source_span)
36-
|| triplets_similar(pt, &gt)
37+
spans_overlap(pt.source_span, gt.source_span) || triplets_similar(pt, &gt)
3738
});
3839

3940
if !dominated {

src/extractor/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ pub fn normalize_predicate(predicate: &str) -> String {
3030

3131
match trimmed {
3232
"co-founded" | "established" => "founded".to_string(),
33-
"heads" | "runs" | "ceo of" | "cto of" | "coo of" | "cfo of"
34-
| "director of" | "president of" | "chairman of" => "leads".to_string(),
33+
"heads" | "runs" | "ceo of" | "cto of" | "coo of" | "cfo of" | "director of"
34+
| "president of" | "chairman of" => "leads".to_string(),
3535
"works for" | "employed at" | "employed by" => "works at".to_string(),
3636
"supervises" | "oversees" => "manages".to_string(),
3737
"based in" | "headquartered in" => "located in".to_string(),

src/extractor/patterns.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -398,9 +398,9 @@ impl PatternMatcher {
398398
for caps in pattern.regex.captures_iter(text) {
399399
if let Some(triplet) = (pattern.extractor)(&caps, text) {
400400
// Avoid duplicate spans
401-
let dominated = seen_spans.iter().any(|(s, e)| {
402-
triplet.source_span.0 >= *s && triplet.source_span.1 <= *e
403-
});
401+
let dominated = seen_spans
402+
.iter()
403+
.any(|(s, e)| triplet.source_span.0 >= *s && triplet.source_span.1 <= *e);
404404
if !dominated {
405405
seen_spans.push(triplet.source_span);
406406
triplets.push(triplet);

src/main.rs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,15 @@ async fn main() -> anyhow::Result<()> {
152152
}
153153
println!("Total: {} triplets from file", total);
154154
}
155-
cli::Commands::Recall { query, limit, min_strength } => {
156-
println!("Recalling memories for: {} (min_strength: {})", query, min_strength);
155+
cli::Commands::Recall {
156+
query,
157+
limit,
158+
min_strength,
159+
} => {
160+
println!(
161+
"Recalling memories for: {} (min_strength: {})",
162+
query, min_strength
163+
);
157164
let retriever = HybridRetriever::new(&storage);
158165
let request = RecallRequest {
159166
query,
@@ -165,7 +172,11 @@ async fn main() -> anyhow::Result<()> {
165172
for m in response.memories {
166173
println!(
167174
"- {} -> {} -> {} (strength: {:.2}, conf: {:.2})",
168-
m.subject_node.label, m.edge.predicate, m.object_node.label, m.relevance_score, m.edge.confidence
175+
m.subject_node.label,
176+
m.edge.predicate,
177+
m.object_node.label,
178+
m.relevance_score,
179+
m.edge.confidence
169180
);
170181
}
171182
}
@@ -203,10 +214,16 @@ async fn main() -> anyhow::Result<()> {
203214
cli::Commands::Dedup => {
204215
println!("Running Node Deduplication...");
205216
let nodes = storage.list_nodes()?;
206-
let mut normalized_map: std::collections::HashMap<String, Vec<Node>> = std::collections::HashMap::new();
217+
let mut normalized_map: std::collections::HashMap<String, Vec<Node>> =
218+
std::collections::HashMap::new();
207219

208220
for node in nodes {
209-
let norm = node.label.to_lowercase().chars().filter(|c| c.is_alphanumeric()).collect::<String>();
221+
let norm = node
222+
.label
223+
.to_lowercase()
224+
.chars()
225+
.filter(|c| c.is_alphanumeric())
226+
.collect::<String>();
210227
normalized_map.entry(norm).or_default().push(node);
211228
}
212229

@@ -215,15 +232,22 @@ async fn main() -> anyhow::Result<()> {
215232
if group.len() > 1 && !norm.is_empty() {
216233
let winner = &group[0];
217234
for loser in &group[1..] {
218-
println!("Merging '{}' (id: {}) -> '{}' (id: {})", loser.label, loser.id, winner.label, winner.id);
235+
println!(
236+
"Merging '{}' (id: {}) -> '{}' (id: {})",
237+
loser.label, loser.id, winner.label, winner.id
238+
);
219239
storage.merge_nodes(&winner.id, &loser.id)?;
220240
merged_count += 1;
221241
}
222242
}
223243
}
224244
println!("Deduplication complete. Merged {} nodes.", merged_count);
225245
}
226-
cli::Commands::Benchmark { cases, verbose, mode } => {
246+
cli::Commands::Benchmark {
247+
cases,
248+
verbose,
249+
mode,
250+
} => {
227251
println!("Loading test cases from: {}", cases.display());
228252
let test_cases = benchmark::load_test_cases(&cases)?;
229253

src/mcp.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
//!
33
//! Contains the MCPServer struct with all tool handlers, and the SSE transport layer.
44
5+
use crate::graph::{Edge, GraphStore, Node, NodeType};
6+
use crate::retriever::{search::HybridRetriever, RecallRequest, Retriever};
7+
use crate::storage::sqlite::SqliteStorage;
58
use anyhow::Result;
69
use axum::{
710
extract::{Query, State as AxumState},
@@ -14,9 +17,6 @@ use axum::{
1417
Json, Router,
1518
};
1619
use futures::stream::Stream;
17-
use crate::graph::{Edge, GraphStore, Node, NodeType};
18-
use crate::retriever::{search::HybridRetriever, RecallRequest, Retriever};
19-
use crate::storage::sqlite::SqliteStorage;
2020
use serde::{Deserialize, Serialize};
2121
use serde_json::json;
2222
use std::collections::HashMap;
@@ -666,7 +666,11 @@ pub async fn sse_handler(
666666
let session_id = uuid::Uuid::new_v4().to_string();
667667
let (tx, rx) = mpsc::unbounded_channel::<String>();
668668

669-
state.sessions.lock().await.insert(session_id.clone(), tx.clone());
669+
state
670+
.sessions
671+
.lock()
672+
.await
673+
.insert(session_id.clone(), tx.clone());
670674

671675
let endpoint_url = format!("/message?session_id={}", session_id);
672676
let _ = tx.send(format!("__endpoint__{}", endpoint_url));
@@ -808,7 +812,10 @@ pub async fn run_sse(server: MCPServer, port: u16) -> Result<()> {
808812

809813
let addr = std::net::SocketAddr::from(([127, 0, 0, 1], port));
810814
eprintln!("[orunla] SSE transport listening on http://{}", addr);
811-
eprintln!("[orunla] Connect your MCP client to http://localhost:{}/sse", port);
815+
eprintln!(
816+
"[orunla] Connect your MCP client to http://localhost:{}/sse",
817+
port
818+
);
812819

813820
let listener = tokio::net::TcpListener::bind(addr).await?;
814821
axum::serve(listener, app.into_make_service()).await?;

src/retriever/search.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ impl<'a> Retriever for HybridRetriever<'a> {
2222
let mut memories = Vec::new();
2323
for edge in edges {
2424
let strength = calculate_strength(&edge, now);
25-
25+
2626
if edge.confidence >= request.min_confidence && strength >= request.min_strength {
2727
let subject_node = self.store.get_node(&edge.source)?.unwrap_or_else(|| {
2828
crate::graph::Node::new("Unknown".to_string(), crate::graph::NodeType::Unknown)

src/server/mod.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use axum::{
1515
use serde::Deserialize;
1616
use serde_json::{json, Value};
1717
use std::collections::HashMap;
18-
use std::net::{SocketAddr, IpAddr};
18+
use std::net::{IpAddr, SocketAddr};
1919
use std::sync::Arc;
2020
use std::time::{Duration, Instant};
2121
use tokio::sync::Mutex;
@@ -130,7 +130,11 @@ async fn auth_middleware(
130130
Err(StatusCode::UNAUTHORIZED)
131131
}
132132

133-
pub async fn start_server(storage: SqliteStorage, port: u16, api_key: Option<String>) -> anyhow::Result<()> {
133+
pub async fn start_server(
134+
storage: SqliteStorage,
135+
port: u16,
136+
api_key: Option<String>,
137+
) -> anyhow::Result<()> {
134138
println!("Initializing hybrid extractor (Patterns + GliNER)...");
135139
let extractor = Arc::new(HybridExtractor::new()?);
136140
let rate_limiter = Arc::new(RateLimiter::new(60)); // 60 requests per minute per IP
@@ -477,7 +481,9 @@ pub async fn delete_memory_handler(
477481
match storage.delete_edge(&id) {
478482
Ok(_) => {
479483
let orphaned = storage.cleanup_orphaned_nodes().unwrap_or(0);
480-
Json(json!({ "status": "ok", "message": format!("Memory deleted. Cleaned up {} orphaned nodes.", orphaned) }))
484+
Json(
485+
json!({ "status": "ok", "message": format!("Memory deleted. Cleaned up {} orphaned nodes.", orphaned) }),
486+
)
481487
}
482488
Err(_e) => {
483489
eprintln!("Delete error: {}", _e); // Log server-side only

0 commit comments

Comments
 (0)