feat(memory): add nightly vault index rebuild and agent docs
Add maybeRebuildVaultIndex() to heartbeat service for nightly full index rebuilds during quiet hours (2-5am). Uses a date stamp file to run at most once per day. Update AGENT.md with memory vault conventions, note format, and tool usage guidelines.
This commit is contained in:
parent
1102a64715
commit
ac5b384f16
2 changed files with 70 additions and 2 deletions
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"github.com/sipeed/picoclaw/pkg/bus"
|
"github.com/sipeed/picoclaw/pkg/bus"
|
||||||
"github.com/sipeed/picoclaw/pkg/constants"
|
"github.com/sipeed/picoclaw/pkg/constants"
|
||||||
"github.com/sipeed/picoclaw/pkg/logger"
|
"github.com/sipeed/picoclaw/pkg/logger"
|
||||||
|
"github.com/sipeed/picoclaw/pkg/memory"
|
||||||
"github.com/sipeed/picoclaw/pkg/state"
|
"github.com/sipeed/picoclaw/pkg/state"
|
||||||
"github.com/sipeed/picoclaw/pkg/tools"
|
"github.com/sipeed/picoclaw/pkg/tools"
|
||||||
)
|
)
|
||||||
|
|
@ -159,6 +160,9 @@ func (hs *HeartbeatService) executeHeartbeat() {
|
||||||
|
|
||||||
logger.DebugC("heartbeat", "Executing heartbeat")
|
logger.DebugC("heartbeat", "Executing heartbeat")
|
||||||
|
|
||||||
|
// Nightly vault index rebuild (runs once per day between 2-5am)
|
||||||
|
hs.maybeRebuildVaultIndex()
|
||||||
|
|
||||||
prompt := hs.buildPrompt()
|
prompt := hs.buildPrompt()
|
||||||
if prompt == "" {
|
if prompt == "" {
|
||||||
logger.InfoC("heartbeat", "No heartbeat prompt (HEARTBEAT.md empty or missing)")
|
logger.InfoC("heartbeat", "No heartbeat prompt (HEARTBEAT.md empty or missing)")
|
||||||
|
|
@ -341,6 +345,37 @@ func (hs *HeartbeatService) parseLastChannel(lastChannel string) (platform, user
|
||||||
return platform, userID
|
return platform, userID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// maybeRebuildVaultIndex performs a nightly full rebuild of the memory vault
|
||||||
|
// index. It runs at most once per day, during quiet hours (2-5am local time),
|
||||||
|
// to catch any inconsistencies from incremental updates.
|
||||||
|
func (hs *HeartbeatService) maybeRebuildVaultIndex() {
|
||||||
|
memoryDir := filepath.Join(hs.workspace, "memory")
|
||||||
|
stampFile := filepath.Join(memoryDir, ".last_rebuild")
|
||||||
|
today := time.Now().Format("2006-01-02")
|
||||||
|
|
||||||
|
// Check if already rebuilt today
|
||||||
|
if data, err := os.ReadFile(stampFile); err == nil {
|
||||||
|
if strings.TrimSpace(string(data)) == today {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only rebuild during quiet hours (2am-5am)
|
||||||
|
hour := time.Now().Hour()
|
||||||
|
if hour < 2 || hour >= 5 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
vault := memory.NewVault(memoryDir)
|
||||||
|
if err := vault.RebuildIndex(); err != nil {
|
||||||
|
hs.logError("Vault index rebuild failed: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
os.WriteFile(stampFile, []byte(today), 0o644)
|
||||||
|
hs.logInfo("Nightly vault index rebuild completed")
|
||||||
|
}
|
||||||
|
|
||||||
// logInfo logs an informational message to the heartbeat log
|
// logInfo logs an informational message to the heartbeat log
|
||||||
func (hs *HeartbeatService) logInfo(format string, args ...any) {
|
func (hs *HeartbeatService) logInfo(format string, args ...any) {
|
||||||
hs.log("INFO", format, args...)
|
hs.log("INFO", format, args...)
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,39 @@ You are a helpful AI assistant. Be concise, accurate, and friendly.
|
||||||
- Always explain what you're doing before taking actions
|
- Always explain what you're doing before taking actions
|
||||||
- Ask for clarification when request is ambiguous
|
- Ask for clarification when request is ambiguous
|
||||||
- Use tools to help accomplish tasks
|
- Use tools to help accomplish tasks
|
||||||
- Remember important information in your memory files
|
- Remember important information using the memory vault (see below)
|
||||||
- Be proactive and helpful
|
- Be proactive and helpful
|
||||||
- Learn from user feedback
|
- Learn from user feedback
|
||||||
|
|
||||||
|
## Memory Vault
|
||||||
|
|
||||||
|
Your memory is an Obsidian-compatible vault of markdown notes in `memory/`. Each note has YAML frontmatter for metadata.
|
||||||
|
|
||||||
|
### Note Format
|
||||||
|
|
||||||
|
```
|
||||||
|
---
|
||||||
|
title: Note Title Here
|
||||||
|
created: 2026-02-23
|
||||||
|
updated: 2026-02-23
|
||||||
|
tags: [tag1, tag2]
|
||||||
|
aliases: [alternate-name]
|
||||||
|
---
|
||||||
|
|
||||||
|
Content here. Link to other notes with [[note-title]].
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tools
|
||||||
|
|
||||||
|
- **memory_save** — Save knowledge with structured frontmatter and tags. Auto-generates frontmatter, preserves created dates on updates, and rebuilds the vault index.
|
||||||
|
- **memory_search** — Search by tags (AND logic) or text query matching title/tags/aliases. Returns metadata; use memory_recall to read full content.
|
||||||
|
- **memory_recall** — Read full note content by exact path or by topic (searches and reads top matches).
|
||||||
|
|
||||||
|
### Conventions
|
||||||
|
|
||||||
|
- Folders are for human convenience (e.g. `topics/`, `people/`, `projects/`), not enforced by code
|
||||||
|
- Tags are the primary organizational mechanism
|
||||||
|
- Daily notes (`YYYYMM/YYYYMMDD.md`) are stored alongside vault notes
|
||||||
|
- The index at `_index.md` is auto-generated — never edit it manually
|
||||||
|
- When you learn something new about the user or a topic, save a note
|
||||||
|
- When answering questions, check memory first with memory_search or memory_recall
|
||||||
Loading…
Add table
Reference in a new issue