feat(agent): wire JSONL session store into agent loop

Replace the concrete *SessionManager field with the SessionStore
interface and initialize the JSONL backend by default. Legacy .json
session files are auto-migrated on first startup. Falls back to
SessionManager if the JSONL store cannot be initialized.

The agent loop code (loop.go) requires zero changes — all method
calls work identically through the interface.

Closes #1169
This commit is contained in:
xiaoen 2026-03-06 12:49:41 +08:00
parent 317d998ea5
commit d9e8278028

View file

@ -1,6 +1,7 @@
package agent package agent
import ( import (
"context"
"fmt" "fmt"
"log" "log"
"os" "os"
@ -9,6 +10,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"
@ -31,7 +33,7 @@ type AgentInstance struct {
SummarizeMessageThreshold int SummarizeMessageThreshold int
SummarizeTokenPercent int SummarizeTokenPercent int
Provider providers.LLMProvider Provider providers.LLMProvider
Sessions *session.SessionManager Sessions session.SessionStore
ContextBuilder *ContextBuilder ContextBuilder *ContextBuilder
Tools *tools.ToolRegistry Tools *tools.ToolRegistry
Subagents *config.SubagentsConfig Subagents *config.SubagentsConfig
@ -86,7 +88,7 @@ func NewAgentInstance(
} }
sessionsDir := filepath.Join(workspace, "sessions") sessionsDir := filepath.Join(workspace, "sessions")
sessionsManager := session.NewSessionManager(sessionsDir) sessions := initSessionStore(sessionsDir)
contextBuilder := NewContextBuilder(workspace) contextBuilder := NewContextBuilder(workspace)
@ -194,7 +196,7 @@ func NewAgentInstance(
SummarizeMessageThreshold: summarizeMessageThreshold, SummarizeMessageThreshold: summarizeMessageThreshold,
SummarizeTokenPercent: summarizeTokenPercent, SummarizeTokenPercent: summarizeTokenPercent,
Provider: provider, Provider: provider,
Sessions: sessionsManager, Sessions: sessions,
ContextBuilder: contextBuilder, ContextBuilder: contextBuilder,
Tools: toolsRegistry, Tools: toolsRegistry,
Subagents: subagents, Subagents: subagents,
@ -246,6 +248,25 @@ func compilePatterns(patterns []string) []*regexp.Regexp {
return compiled return compiled
} }
// initSessionStore creates the session persistence backend.
// It uses the JSONL store by default and auto-migrates legacy JSON sessions.
// Falls back to SessionManager if the JSONL store cannot be initialized.
func initSessionStore(dir string) session.SessionStore {
store, err := memory.NewJSONLStore(dir)
if err != nil {
log.Printf("memory: init store: %v; using json sessions", err)
return session.NewSessionManager(dir)
}
if n, merr := memory.MigrateFromJSON(context.Background(), dir, store); merr != nil {
log.Printf("memory: migration: %v", merr)
} else if n > 0 {
log.Printf("memory: migrated %d session(s) to jsonl", n)
}
return session.NewJSONLBackend(store)
}
func expandHome(path string) string { func expandHome(path string) string {
if path == "" { if path == "" {
return path return path