Skip to main content

codetether_agent/knowledge_graph/
graph.rs

1//! Core graph data structure for the code knowledge graph.
2
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6/// A node in the knowledge graph (function, struct, module, etc.).
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct CodeNode {
9    pub id: String,
10    pub name: String,
11    pub kind: CodeNodeKind,
12    pub file_path: String,
13    pub line: u32,
14    pub embedding: Option<Vec<f32>>,
15    pub last_modified: chrono::DateTime<chrono::Utc>,
16}
17
18#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
19#[serde(rename_all = "snake_case")]
20pub enum CodeNodeKind {
21    Function,
22    Struct,
23    Enum,
24    Trait,
25    Module,
26    Const,
27    TypeAlias,
28}
29
30/// An edge between two nodes (calls, imports, implements, etc.).
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct CodeEdge {
33    pub source_id: String,
34    pub target_id: String,
35    pub kind: EdgeKind,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
39#[serde(rename_all = "snake_case")]
40pub enum EdgeKind {
41    Calls,
42    Imports,
43    Implements,
44    Contains,
45    References,
46}
47
48/// The in-memory knowledge graph.
49#[derive(Debug, Default, Serialize, Deserialize)]
50pub struct KnowledgeGraph {
51    pub nodes: HashMap<String, CodeNode>,
52    pub edges: Vec<CodeEdge>,
53}
54
55impl KnowledgeGraph {
56    pub fn callers_of(&self, node_id: &str) -> Vec<&CodeNode> {
57        self.edges
58            .iter()
59            .filter(|e| e.target_id == node_id && e.kind == EdgeKind::Calls)
60            .filter_map(|e| self.nodes.get(&e.source_id))
61            .collect()
62    }
63
64    pub fn symbols_in_file(&self, path: &str) -> Vec<&CodeNode> {
65        self.nodes
66            .values()
67            .filter(|n| n.file_path == path)
68            .collect()
69    }
70}