mirror of
https://github.com/lukaszraczylo/claude-mnemonic.git
synced 2026-06-09 23:59:40 +00:00
f79782a008
* Resolves issue #13 - Switched model to bge-small-en-v1.5 - Added lazy re-embedding - Added model version tracking per vector - Added conversion of vectors to the new model * Add lfs support to the workflow. * Implements importance scoring with decay + voting #6 * Resolves issue #5 by marking observations as superseeded and scheduled for deletion * Implement pattern detection #7 * Improve injections and observations accuracy - Session start: Recent observations for project context (recency-based) - User prompt: Semantically relevant observations (similarity-based with threshold) * Added two stage retrieval with bi and cross encoder #8 * Implement query expansion and reformulation #9 * Knowledge graph and relationships ( resolves #4 ) - File Overlap Detection: Detects relationships when observations modify/read the same files - Concept Overlap Detection: Detects relationships based on shared semantic concepts - Type Progression Detection: Infers relationships from natural observation type progressions (e.g., discovery → bugfix = "fixes") - Temporal Proximity Detection: Detects relationships between observations in the same session within 5 minutes - Narrative Mention Detection: Detects explicit relationship language in narratives (e.g., "fixes", "depends on", "supersedes") * Add visualisation of the relations to the dashboard. * fixup! Add visualisation of the relations to the dashboard. * Update documentation with new settings and screenshots.
175 lines
4.6 KiB
Go
175 lines
4.6 KiB
Go
// Package worker provides the main worker service for claude-mnemonic.
|
|
package worker
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/lukaszraczylo/claude-mnemonic/pkg/models"
|
|
)
|
|
|
|
// DefaultRelationsLimit is the default number of relations to return.
|
|
const DefaultRelationsLimit = 50
|
|
|
|
// handleGetRelations returns relations for an observation.
|
|
func (s *Service) handleGetRelations(w http.ResponseWriter, r *http.Request) {
|
|
idStr := chi.URLParam(r, "id")
|
|
id, err := strconv.ParseInt(idStr, 10, 64)
|
|
if err != nil {
|
|
http.Error(w, "invalid observation id", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
relations, err := s.relationStore.GetRelationsWithDetails(r.Context(), id)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if relations == nil {
|
|
relations = []*models.RelationWithDetails{}
|
|
}
|
|
|
|
writeJSON(w, relations)
|
|
}
|
|
|
|
// handleGetRelationGraph returns the relation graph for an observation.
|
|
func (s *Service) handleGetRelationGraph(w http.ResponseWriter, r *http.Request) {
|
|
idStr := chi.URLParam(r, "id")
|
|
id, err := strconv.ParseInt(idStr, 10, 64)
|
|
if err != nil {
|
|
http.Error(w, "invalid observation id", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
// Get depth parameter (default 2)
|
|
depth := 2
|
|
if depthStr := r.URL.Query().Get("depth"); depthStr != "" {
|
|
if d, err := strconv.Atoi(depthStr); err == nil && d > 0 && d <= 5 {
|
|
depth = d
|
|
}
|
|
}
|
|
|
|
graph, err := s.relationStore.GetRelationGraph(r.Context(), id, depth)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
writeJSON(w, graph)
|
|
}
|
|
|
|
// handleGetRelatedObservations returns observations related to a given one.
|
|
func (s *Service) handleGetRelatedObservations(w http.ResponseWriter, r *http.Request) {
|
|
idStr := chi.URLParam(r, "id")
|
|
id, err := strconv.ParseInt(idStr, 10, 64)
|
|
if err != nil {
|
|
http.Error(w, "invalid observation id", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
// Get minimum confidence parameter (default 0.4)
|
|
minConfidence := 0.4
|
|
if confStr := r.URL.Query().Get("min_confidence"); confStr != "" {
|
|
if c, err := strconv.ParseFloat(confStr, 64); err == nil && c >= 0 && c <= 1 {
|
|
minConfidence = c
|
|
}
|
|
}
|
|
|
|
// Get related observation IDs
|
|
relatedIDs, err := s.relationStore.GetRelatedObservationIDs(r.Context(), id, minConfidence)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if len(relatedIDs) == 0 {
|
|
writeJSON(w, []*models.Observation{})
|
|
return
|
|
}
|
|
|
|
// Fetch full observations
|
|
observations, err := s.observationStore.GetObservationsByIDs(r.Context(), relatedIDs, "importance", 50)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if observations == nil {
|
|
observations = []*models.Observation{}
|
|
}
|
|
|
|
writeJSON(w, observations)
|
|
}
|
|
|
|
// handleGetRelationsByType returns all relations of a specific type.
|
|
func (s *Service) handleGetRelationsByType(w http.ResponseWriter, r *http.Request) {
|
|
relType := chi.URLParam(r, "type")
|
|
|
|
// Validate relation type
|
|
validType := false
|
|
for _, t := range models.AllRelationTypes {
|
|
if string(t) == relType {
|
|
validType = true
|
|
break
|
|
}
|
|
}
|
|
if !validType {
|
|
http.Error(w, "invalid relation type", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
limit := DefaultRelationsLimit
|
|
if limitStr := r.URL.Query().Get("limit"); limitStr != "" {
|
|
if l, err := strconv.Atoi(limitStr); err == nil && l > 0 && l <= 100 {
|
|
limit = l
|
|
}
|
|
}
|
|
|
|
relations, err := s.relationStore.GetRelationsByType(r.Context(), models.RelationType(relType), limit)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if relations == nil {
|
|
relations = []*models.ObservationRelation{}
|
|
}
|
|
|
|
writeJSON(w, relations)
|
|
}
|
|
|
|
// handleGetRelationStats returns statistics about relations.
|
|
func (s *Service) handleGetRelationStats(w http.ResponseWriter, r *http.Request) {
|
|
// Get total relation count
|
|
totalCount, err := s.relationStore.GetTotalRelationCount(r.Context())
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// Get high confidence relations count
|
|
highConfRelations, err := s.relationStore.GetHighConfidenceRelations(r.Context(), 0.7, 1000)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// Count by relation type
|
|
typeCounts := make(map[string]int)
|
|
for _, t := range models.AllRelationTypes {
|
|
relations, err := s.relationStore.GetRelationsByType(r.Context(), t, 1000)
|
|
if err == nil {
|
|
typeCounts[string(t)] = len(relations)
|
|
}
|
|
}
|
|
|
|
writeJSON(w, map[string]interface{}{
|
|
"total_count": totalCount,
|
|
"high_confidence": len(highConfRelations),
|
|
"by_type": typeCounts,
|
|
"min_confidence_used": 0.4,
|
|
})
|
|
}
|