feat(memory): integrate vault into agent system
Register memory_save, memory_search, memory_recall tools in agent instance. Update GetMemoryContext() to prefer vault _index.md over legacy MEMORY.md with automatic truncation for large indexes. Update system prompt to reference vault tools instead of raw MEMORY.md editing.
This commit is contained in:
parent
ed8725448a
commit
1102a64715
3 changed files with 40 additions and 12 deletions
|
|
@ -68,7 +68,8 @@ You are picoclaw, a helpful AI assistant.
|
||||||
|
|
||||||
## Workspace
|
## Workspace
|
||||||
Your workspace is at: %s
|
Your workspace is at: %s
|
||||||
- Memory: %s/memory/MEMORY.md
|
- Memory Vault: %s/memory/ (use memory_save, memory_search, memory_recall tools)
|
||||||
|
- Vault Index: %s/memory/_index.md (auto-generated)
|
||||||
- Daily Notes: %s/memory/YYYYMM/YYYYMMDD.md
|
- Daily Notes: %s/memory/YYYYMM/YYYYMMDD.md
|
||||||
- Skills: %s/skills/{skill-name}/SKILL.md
|
- Skills: %s/skills/{skill-name}/SKILL.md
|
||||||
|
|
||||||
|
|
@ -80,8 +81,8 @@ Your workspace is at: %s
|
||||||
|
|
||||||
2. **Be helpful and accurate** - When using tools, briefly explain what you're doing.
|
2. **Be helpful and accurate** - When using tools, briefly explain what you're doing.
|
||||||
|
|
||||||
3. **Memory** - When interacting with me if something seems memorable, update %s/memory/MEMORY.md`,
|
3. **Memory** - When something seems memorable, use the memory_save tool to save structured notes with tags. Use memory_recall to retrieve past knowledge.`,
|
||||||
now, runtime, workspacePath, workspacePath, workspacePath, workspacePath, toolsSection, workspacePath)
|
now, runtime, workspacePath, workspacePath, workspacePath, workspacePath, workspacePath, toolsSection)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cb *ContextBuilder) buildToolsSection() string {
|
func (cb *ContextBuilder) buildToolsSection() string {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/sipeed/picoclaw/pkg/config"
|
"github.com/sipeed/picoclaw/pkg/config"
|
||||||
|
"github.com/sipeed/picoclaw/pkg/memory"
|
||||||
"github.com/sipeed/picoclaw/pkg/providers"
|
"github.com/sipeed/picoclaw/pkg/providers"
|
||||||
"github.com/sipeed/picoclaw/pkg/routing"
|
"github.com/sipeed/picoclaw/pkg/routing"
|
||||||
"github.com/sipeed/picoclaw/pkg/session"
|
"github.com/sipeed/picoclaw/pkg/session"
|
||||||
|
|
@ -55,6 +56,12 @@ func NewAgentInstance(
|
||||||
toolsRegistry.Register(tools.NewEditFileTool(workspace, restrict))
|
toolsRegistry.Register(tools.NewEditFileTool(workspace, restrict))
|
||||||
toolsRegistry.Register(tools.NewAppendFileTool(workspace, restrict))
|
toolsRegistry.Register(tools.NewAppendFileTool(workspace, restrict))
|
||||||
|
|
||||||
|
// Memory vault tools
|
||||||
|
memVault := memory.NewVault(filepath.Join(workspace, "memory"))
|
||||||
|
toolsRegistry.Register(tools.NewMemorySaveTool(memVault))
|
||||||
|
toolsRegistry.Register(tools.NewMemorySearchTool(memVault))
|
||||||
|
toolsRegistry.Register(tools.NewMemoryRecallTool(memVault))
|
||||||
|
|
||||||
// Configure security middleware from config
|
// Configure security middleware from config
|
||||||
if cfg != nil {
|
if cfg != nil {
|
||||||
sec := cfg.Tools.Security
|
sec := cfg.Tools.Security
|
||||||
|
|
|
||||||
|
|
@ -12,15 +12,18 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/sipeed/picoclaw/pkg/memory"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MemoryStore manages persistent memory for the agent.
|
// MemoryStore manages persistent memory for the agent.
|
||||||
// - Long-term memory: memory/MEMORY.md
|
// It supports both the legacy MEMORY.md format and the new vault-based
|
||||||
// - Daily notes: memory/YYYYMM/YYYYMMDD.md
|
// index system. When a vault _index.md exists, it is preferred over MEMORY.md.
|
||||||
type MemoryStore struct {
|
type MemoryStore struct {
|
||||||
workspace string
|
workspace string
|
||||||
memoryDir string
|
memoryDir string
|
||||||
memoryFile string
|
memoryFile string
|
||||||
|
vault *memory.Vault
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMemoryStore creates a new MemoryStore with the given workspace path.
|
// NewMemoryStore creates a new MemoryStore with the given workspace path.
|
||||||
|
|
@ -36,6 +39,7 @@ func NewMemoryStore(workspace string) *MemoryStore {
|
||||||
workspace: workspace,
|
workspace: workspace,
|
||||||
memoryDir: memoryDir,
|
memoryDir: memoryDir,
|
||||||
memoryFile: memoryFile,
|
memoryFile: memoryFile,
|
||||||
|
vault: memory.NewVault(memoryDir),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -123,24 +127,40 @@ func (ms *MemoryStore) GetRecentDailyNotes(days int) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMemoryContext returns formatted memory context for the agent prompt.
|
// GetMemoryContext returns formatted memory context for the agent prompt.
|
||||||
// Includes long-term memory and recent daily notes.
|
// Prefers the vault index (_index.md) when available, falling back to
|
||||||
|
// the legacy MEMORY.md. Recent daily notes are always included.
|
||||||
func (ms *MemoryStore) GetMemoryContext() string {
|
func (ms *MemoryStore) GetMemoryContext() string {
|
||||||
longTerm := ms.ReadLongTerm()
|
// Prefer vault index over legacy MEMORY.md
|
||||||
|
index := ms.vault.ReadIndex()
|
||||||
|
if index == "" {
|
||||||
|
index = ms.ReadLongTerm()
|
||||||
|
}
|
||||||
|
|
||||||
recentNotes := ms.GetRecentDailyNotes(3)
|
recentNotes := ms.GetRecentDailyNotes(3)
|
||||||
|
|
||||||
if longTerm == "" && recentNotes == "" {
|
if index == "" && recentNotes == "" {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
|
|
||||||
if longTerm != "" {
|
if index != "" {
|
||||||
sb.WriteString("## Long-term Memory\n\n")
|
sb.WriteString("## Memory Vault Index\n\n")
|
||||||
sb.WriteString(longTerm)
|
// Truncate if too large for system prompt
|
||||||
|
if len(index) > 4000 {
|
||||||
|
if tableEnd := strings.Index(index, "\n## Tags"); tableEnd > 0 {
|
||||||
|
sb.WriteString(index[:tableEnd])
|
||||||
|
} else {
|
||||||
|
sb.WriteString(index[:4000])
|
||||||
|
sb.WriteString("\n\n(Index truncated. Use memory_search for full details.)")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sb.WriteString(index)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if recentNotes != "" {
|
if recentNotes != "" {
|
||||||
if longTerm != "" {
|
if index != "" {
|
||||||
sb.WriteString("\n\n---\n\n")
|
sb.WriteString("\n\n---\n\n")
|
||||||
}
|
}
|
||||||
sb.WriteString("## Recent Daily Notes\n\n")
|
sb.WriteString("## Recent Daily Notes\n\n")
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue