Add memory system, debug mode, and tools

This commit is contained in:
yinwm
2026-02-10 16:05:23 +08:00
parent be2ed5d759
commit 10442732b4
7 changed files with 579 additions and 53 deletions

View File

@@ -4,8 +4,11 @@ import (
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/sipeed/picoclaw/pkg/logger"
"github.com/sipeed/picoclaw/pkg/providers"
"github.com/sipeed/picoclaw/pkg/skills"
)
@@ -13,6 +16,7 @@ import (
type ContextBuilder struct {
workspace string
skillsLoader *skills.SkillsLoader
memory *MemoryStore
}
func NewContextBuilder(workspace string) *ContextBuilder {
@@ -20,12 +24,14 @@ func NewContextBuilder(workspace string) *ContextBuilder {
return &ContextBuilder{
workspace: workspace,
skillsLoader: skills.NewSkillsLoader(workspace, builtinSkillsDir),
memory: NewMemoryStore(workspace),
}
}
func (cb *ContextBuilder) BuildSystemPrompt() string {
func (cb *ContextBuilder) getIdentity() string {
now := time.Now().Format("2006-01-02 15:04 (Monday)")
workspacePath, _ := filepath.Abs(filepath.Join(cb.workspace))
runtime := fmt.Sprintf("%s %s, Go %s", runtime.GOOS, runtime.GOARCH, runtime.Version())
return fmt.Sprintf(`# picoclaw 🦞
@@ -39,6 +45,9 @@ You are picoclaw, a helpful AI assistant. You have access to tools that allow yo
## Current Time
%s
## Runtime
%s
## Workspace
Your workspace is at: %s
- Memory files: %s/memory/MEMORY.md
@@ -60,7 +69,49 @@ For normal conversation, just respond with text - do not call the message tool.
Always be helpful, accurate, and concise. When using tools, explain what you're doing.
When remembering something, write to %s/memory/MEMORY.md`,
now, workspacePath, workspacePath, workspacePath, workspacePath, workspacePath)
now, runtime, workspacePath, workspacePath, workspacePath, workspacePath, workspacePath)
}
func (cb *ContextBuilder) BuildSystemPrompt() string {
parts := []string{}
// Core identity section
parts = append(parts, cb.getIdentity())
// Bootstrap files
bootstrapContent := cb.LoadBootstrapFiles()
if bootstrapContent != "" {
parts = append(parts, bootstrapContent)
}
// Skills - progressive loading
// 1. Always skills: load full content
alwaysSkills := cb.skillsLoader.GetAlwaysSkills()
if len(alwaysSkills) > 0 {
alwaysContent := cb.skillsLoader.LoadSkillsForContext(alwaysSkills)
if alwaysContent != "" {
parts = append(parts, "# Active Skills\n\n"+alwaysContent)
}
}
// 2. Available skills: only show summary
skillsSummary := cb.skillsLoader.BuildSkillsSummary()
if skillsSummary != "" {
parts = append(parts, fmt.Sprintf(`# Skills
The following skills extend your capabilities. To use a skill, read its SKILL.md file.
%s`, skillsSummary))
}
// Memory context
memoryContext := cb.memory.GetMemoryContext()
if memoryContext != "" {
parts = append(parts, "# Memory\n\n"+memoryContext)
}
// Join with "---" separator
return strings.Join(parts, "\n\n---\n\n")
}
func (cb *ContextBuilder) LoadBootstrapFiles() string {
@@ -84,24 +135,28 @@ func (cb *ContextBuilder) LoadBootstrapFiles() string {
return result
}
<<<<<<< HEAD
func (cb *ContextBuilder) BuildMessages(history []providers.Message, summary string, currentMessage string, media []string) []providers.Message {
=======
func (cb *ContextBuilder) BuildMessages(history []providers.Message, summary string, currentMessage string, media []string, channel, chatID string) []providers.Message {
>>>>>>> fd1dd87 (Add memory system, debug mode, and tools)
messages := []providers.Message{}
systemPrompt := cb.BuildSystemPrompt()
bootstrapContent := cb.LoadBootstrapFiles()
if bootstrapContent != "" {
systemPrompt += "\n\n" + bootstrapContent
// Add Current Session info if provided
if channel != "" && chatID != "" {
systemPrompt += fmt.Sprintf("\n\n## Current Session\nChannel: %s\nChat ID: %s", channel, chatID)
}
skillsSummary := cb.skillsLoader.BuildSkillsSummary()
if skillsSummary != "" {
systemPrompt += "\n\n## Available Skills\n\n" + skillsSummary
}
skillsContent := cb.loadSkills()
if skillsContent != "" {
systemPrompt += "\n\n" + skillsContent
}
// Log system prompt for debugging
logger.InfoCF("agent", "System prompt built",
map[string]interface{}{
"total_chars": len(systemPrompt),
"total_lines": strings.Count(systemPrompt, "\n") + 1,
"section_count": strings.Count(systemPrompt, "\n\n---\n\n") + 1,
})
logger.DebugCF("agent", "Full system prompt:\n"+systemPrompt, nil)
if summary != "" {
systemPrompt += "\n\n## Summary of Previous Conversation\n\n" + summary
@@ -160,3 +215,21 @@ func (cb *ContextBuilder) loadSkills() string {
return "# Skill Definitions\n\n" + content
}
// GetSkillsInfo returns information about loaded skills.
func (cb *ContextBuilder) GetSkillsInfo() map[string]interface{} {
allSkills := cb.skillsLoader.ListSkills(true)
skillNames := make([]string, 0, len(allSkills))
availableCount := 0
for _, s := range allSkills {
skillNames = append(skillNames, s.Name)
if s.Available {
availableCount++
}
}
return map[string]interface{}{
"total": len(allSkills),
"available": availableCount,
"names": skillNames,
}
}