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
import (
"context"
"fmt"
"log"
"os"
@ -9,6 +10,7 @@ import (
"strings"
"github.com/sipeed/picoclaw/pkg/config"
"github.com/sipeed/picoclaw/pkg/memory"
"github.com/sipeed/picoclaw/pkg/providers"
"github.com/sipeed/picoclaw/pkg/routing"
"github.com/sipeed/picoclaw/pkg/session"
@ -31,7 +33,7 @@ type AgentInstance struct {
SummarizeMessageThreshold int
SummarizeTokenPercent int
Provider providers.LLMProvider
Sessions *session.SessionManager
Sessions session.SessionStore
ContextBuilder *ContextBuilder
Tools *tools.ToolRegistry
Subagents *config.SubagentsConfig
@ -86,7 +88,7 @@ func NewAgentInstance(
}
sessionsDir := filepath.Join(workspace, "sessions")
sessionsManager := session.NewSessionManager(sessionsDir)
sessions := initSessionStore(sessionsDir)
contextBuilder := NewContextBuilder(workspace)
@ -194,7 +196,7 @@ func NewAgentInstance(
SummarizeMessageThreshold: summarizeMessageThreshold,
SummarizeTokenPercent: summarizeTokenPercent,
Provider: provider,
Sessions: sessionsManager,
Sessions: sessions,
ContextBuilder: contextBuilder,
Tools: toolsRegistry,
Subagents: subagents,
@ -246,6 +248,25 @@ func compilePatterns(patterns []string) []*regexp.Regexp {
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 {
if path == "" {
return path