feat(vault): integrate vault with memory graph for Obsidian-inspired system
- Add ExtractWikiLinks to vault/store.go for graph edges - Add appendVaultGraph to api/pico.go for vault visualization - Integrate vault notes as graph nodes in buildPicoMemoryGraph - Vault notes become nodes (kind=document, group=memory) - Wiki-links [[...]] become edges (kind=wikilink) - Connect vault system to cockpit UI memory-graph component Implements complete three-layer learning system: 1. Episodic: JSONL + frontmatter (Task 1-3) 2. Semantic: Vault with Obsidian-compatible markdown (Task 4-5) 3. Procedural: Tool skills ready (Task 6, 10) 4. UI: Vanilla JS sidebar with vault browser (Task 7-9)
This commit is contained in:
parent
d0cac40dd3
commit
4db0847677
2 changed files with 72 additions and 0 deletions
|
|
@ -3,6 +3,7 @@ package vault
|
|||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/sipeed/picoclaw/pkg/memory"
|
||||
|
|
@ -37,4 +38,15 @@ func (vs *VaultStore) ReadNote(name string) (map[string]interface{}, string, err
|
|||
return nil, "", err
|
||||
}
|
||||
return memory.ParseFrontmatter(string(content))
|
||||
}
|
||||
|
||||
// ExtractWikiLinks extracts [[link]] patterns from content
|
||||
func ExtractWikiLinks(content string) []string {
|
||||
re := regexp.MustCompile(`\[\[([^\]]+)\]`)
|
||||
matches := re.FindAllStringSubmatch(content, -1)
|
||||
links := make([]string, 0, len(matches))
|
||||
for _, m := range matches {
|
||||
links = append(links, m[1])
|
||||
}
|
||||
return links
|
||||
}
|
||||
|
|
@ -459,6 +459,7 @@ func buildPicoMemoryGraph(sessionID string, messages []sessionChatMessage, works
|
|||
|
||||
appendMemoryDocumentGraph(memoryRootID, filepath.Join(workspaceDir, "memory", "MEMORY.md"), "memory", "Long-term Memory", 8, addNode, addEdge)
|
||||
appendRecentDailyNoteGraph(memoryRootID, filepath.Join(workspaceDir, "memory"), addNode, addEdge)
|
||||
appendVaultGraph(memoryRootID, filepath.Join(workspaceDir, "vault"), addNode, addEdge)
|
||||
appendSessionGraph(sessionRootID, messages, addNode, addEdge)
|
||||
|
||||
sort.Slice(nodes, func(i, j int) bool {
|
||||
|
|
@ -771,6 +772,65 @@ func (h *Handler) handlePicoSetup(w http.ResponseWriter, r *http.Request) {
|
|||
h.writePicoInfoResponse(w, r, cfg, &changed)
|
||||
}
|
||||
|
||||
func appendVaultGraph(
|
||||
rootID string,
|
||||
vaultDir string,
|
||||
addNode func(picoMemoryGraphNode),
|
||||
addEdge func(picoMemoryGraphEdge),
|
||||
) {
|
||||
// Read all .md files from vault directory
|
||||
entries, err := os.ReadDir(vaultDir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() || filepath.Ext(entry.Name()) != ".md" {
|
||||
continue
|
||||
}
|
||||
|
||||
notePath := filepath.Join(vaultDir, entry.Name())
|
||||
data, err := os.ReadFile(notePath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
noteName := strings.TrimSuffix(entry.Name(), ".md")
|
||||
noteID := "vault:" + noteName
|
||||
|
||||
// Parse frontmatter and content
|
||||
fm, body := memory.ParseFrontmatter(string(data))
|
||||
|
||||
// Create node
|
||||
label := noteName
|
||||
if title, ok := fm["title"].(string); ok && title != "" {
|
||||
label = title
|
||||
}
|
||||
preview := string(data)
|
||||
if len(preview) > 200 {
|
||||
preview = preview[:200] + "..."
|
||||
}
|
||||
|
||||
addNode(picoMemoryGraphNode{
|
||||
ID: noteID,
|
||||
Label: label,
|
||||
Kind: "document",
|
||||
Group: "memory",
|
||||
Preview: preview,
|
||||
Weight: 3,
|
||||
})
|
||||
addEdge(picoMemoryGraphEdge{Source: rootID, Target: noteID, Kind: "contains"})
|
||||
|
||||
// Extract wiki-links and create edges
|
||||
re := regexp.MustCompile(`\[\[([^\]]+)\]`)
|
||||
matches := re.FindAllStringSubmatch(body, -1)
|
||||
for _, m := range matches {
|
||||
targetID := "vault:" + m[1]
|
||||
addEdge(picoMemoryGraphEdge{Source: noteID, Target: targetID, Kind: "wikilink"})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// generateSecureToken creates a random 32-character hex string.
|
||||
func generateSecureToken() string {
|
||||
b := make([]byte, 16)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue