| 67 | } |
| 68 | |
| 69 | func (cli *ChatCLI) addMemoryNodes(g *knowledge.Graph) { |
| 70 | if cli.memoryStore == nil { |
| 71 | return |
| 72 | } |
| 73 | m := cli.memoryStore.Manager() |
| 74 | |
| 75 | // Projects first, so fact→project edges can resolve by path. |
| 76 | projByPath := make(map[string]string) |
| 77 | for _, p := range m.Projects.GetAll() { |
| 78 | id := "project:" + graphSlug(p.Name) |
| 79 | g.AddNode(knowledge.Node{ID: id, Kind: knowledge.KindProject, Title: p.Name, Summary: p.Description, Weight: float64(p.Priority)}) |
| 80 | if p.Path != "" { |
| 81 | projByPath[p.Path] = id |
| 82 | } |
| 83 | for _, tech := range p.Technologies { |
| 84 | addTag(g, tech) |
| 85 | g.AddEdge(id, tagID(tech), 1) |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | // Facts, with their tags, category and source project. |
| 90 | factByID := make(map[string]string) |
| 91 | for _, f := range m.Facts.GetAll() { |
| 92 | id := "fact:" + f.ID |
| 93 | g.AddNode(knowledge.Node{ID: id, Kind: knowledge.KindFact, Title: graphTitle(f.Content), Summary: f.Content, Weight: f.Score}) |
| 94 | factByID[f.ID] = id |
| 95 | for _, tag := range f.Tags { |
| 96 | addTag(g, tag) |
| 97 | g.AddEdge(id, tagID(tag), 1) |
| 98 | } |
| 99 | if f.Category != "" { |
| 100 | addTag(g, f.Category) |
| 101 | g.AddEdge(id, tagID(f.Category), 0.5) |
| 102 | } |
| 103 | if pid, ok := projByPath[f.SourceProject]; ok { |
| 104 | g.AddEdge(id, pid, 2) |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | // Topics link to their related facts (the relationship already recorded). |
| 109 | for _, tp := range m.Topics.GetAll() { |
| 110 | id := "topic:" + graphSlug(tp.Name) |
| 111 | g.AddNode(knowledge.Node{ID: id, Kind: knowledge.KindTopic, Title: tp.Name, Summary: tp.Summary, Weight: float64(tp.Mentions)}) |
| 112 | for _, fid := range tp.RelatedFacts { |
| 113 | if nfid, ok := factByID[fid]; ok { |
| 114 | g.AddEdge(id, nfid, 2) |
| 115 | } |
| 116 | } |
| 117 | } |
| 118 | |
| 119 | // The user node, linked to declared skills and goals. |
| 120 | if !m.Profile.IsEmpty() { |
| 121 | prof := m.Profile.Get() |
| 122 | name := prof.Name |
| 123 | if name == "" { |
| 124 | name = "user" |
| 125 | } |
| 126 | g.AddNode(knowledge.Node{ID: "profile:user", Kind: knowledge.KindProfile, Title: name, Summary: prof.Role, Weight: 10}) |