Compare commits

...

2 Commits

Author SHA1 Message Date
Ettore Di Giacinto 76d82b1f4c drop unused code, run compaction immediately at start
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
2026-02-14 23:07:47 +01:00
Ettore Di Giacinto 0de2228ba6 chore: allow to choose how we store things in the vector database
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
2026-02-14 22:22:51 +01:00
5 changed files with 87 additions and 53 deletions
+28 -4
View File
@@ -148,10 +148,34 @@ func (a *Agent) saveCurrentConversation(conv Messages) {
xlog.Error("Error storing into memory", "error", err)
}
} else {
for _, message := range conv {
if message.Role == "user" {
if err := a.options.ragdb.Store(message.Content); err != nil {
xlog.Error("Error storing into memory", "error", err)
// Use the conversation storage mode to determine what to store
switch a.options.conversationStorageMode {
case StoreWholeConversation:
// Store the entire conversation as a single block
if len(conv) > 0 {
convStr := Messages(conv).String()
if err := a.options.ragdb.Store(convStr); err != nil {
xlog.Error("Error storing whole conversation into memory", "error", err)
}
}
case StoreUserAndAssistant:
// Store user and assistant messages separately
for _, message := range conv {
if message.Role == "user" || message.Role == "assistant" {
if err := a.options.ragdb.Store(message.Content); err != nil {
xlog.Error("Error storing message into memory", "error", err, "role", message.Role)
}
}
}
case StoreUserOnly:
fallthrough
default:
// Store only user messages (default behavior)
for _, message := range conv {
if message.Role == "user" {
if err := a.options.ragdb.Store(message.Content); err != nil {
xlog.Error("Error storing into memory", "error", err)
}
}
}
}
+33 -38
View File
@@ -10,6 +10,18 @@ import (
type Option func(*options) error
// ConversationStorageMode defines how conversations are stored in the knowledge base
type ConversationStorageMode string
const (
// StoreUserOnly stores only user messages (default)
StoreUserOnly ConversationStorageMode = "user_only"
// StoreUserAndAssistant stores both user and assistant messages separately
StoreUserAndAssistant ConversationStorageMode = "user_and_assistant"
// StoreWholeConversation stores the entire conversation as a single block
StoreWholeConversation ConversationStorageMode = "whole_conversation"
)
type llmOptions struct {
APIURL string
APIKey string
@@ -31,6 +43,7 @@ type options struct {
enableHUD, standaloneJob, showCharacter, enableKB, enableSummaryMemory, enableLongTermMemory bool
stripThinkingTags bool
kbAutoSearch bool
conversationStorageMode ConversationStorageMode
canStopItself bool
initiateConversations bool
@@ -49,11 +62,6 @@ type options struct {
kbResults int
ragdb RAGDB
// KB compaction (when enableKB is true)
enableKBCompaction bool
kbCompactionInterval string // "daily", "weekly", "monthly"
kbCompactionSummarize bool
// Evaluation settings
maxEvaluationLoops int
enableEvaluation bool
@@ -85,12 +93,13 @@ func (o *options) SeparatedMultimodalModel() bool {
func defaultOptions() *options {
return &options{
parallelJobs: 1,
periodicRuns: 15 * time.Minute,
schedulerPollInterval: 30 * time.Second,
maxEvaluationLoops: 2,
enableEvaluation: false,
kbAutoSearch: true, // Default to true to maintain backward compatibility
parallelJobs: 1,
periodicRuns: 15 * time.Minute,
schedulerPollInterval: 30 * time.Second,
maxEvaluationLoops: 2,
enableEvaluation: false,
kbAutoSearch: true, // Default to true to maintain backward compatibility
conversationStorageMode: StoreUserOnly, // Default to user-only for backward compatibility
LLMAPI: llmOptions{
APIURL: "http://localhost:8080",
Model: "gpt-4",
@@ -166,33 +175,6 @@ func EnableKnowledgeBaseWithResults(results int) Option {
}
}
// EnableKBCompaction enables periodic KB compaction (group by date, optionally summarize, store, delete originals).
var EnableKBCompaction = func(o *options) error {
o.enableKBCompaction = true
return nil
}
// WithKBCompactionInterval sets the compaction window: "daily", "weekly", or "monthly".
func WithKBCompactionInterval(interval string) Option {
return func(o *options) error {
switch interval {
case "daily", "weekly", "monthly":
o.kbCompactionInterval = interval
default:
o.kbCompactionInterval = "daily"
}
return nil
}
}
// WithKBCompactionSummarize sets whether compaction uses LLM to summarize (true) or just concatenates (false).
func WithKBCompactionSummarize(summarize bool) Option {
return func(o *options) error {
o.kbCompactionSummarize = summarize
return nil
}
}
func WithLastMessageDuration(duration string) Option {
return func(o *options) error {
d, err := time.ParseDuration(duration)
@@ -269,6 +251,19 @@ func WithRAGDB(db RAGDB) Option {
}
}
// WithConversationStorageMode sets how conversations are stored in the knowledge base
func WithConversationStorageMode(mode ConversationStorageMode) Option {
return func(o *options) error {
switch mode {
case StoreUserOnly, StoreUserAndAssistant, StoreWholeConversation:
o.conversationStorageMode = mode
default:
o.conversationStorageMode = StoreUserOnly
}
return nil
}
}
func WithSystemPrompt(prompt string) Option {
return func(o *options) error {
o.systemPrompt = prompt
+5
View File
@@ -183,6 +183,11 @@ func RunCompaction(ctx context.Context, client *localrag.WrappedClient, period s
// runCompactionTicker runs compaction on a schedule (daily/weekly/monthly). It stops when ctx is done.
func runCompactionTicker(ctx context.Context, client *localrag.WrappedClient, config *AgentConfig, apiURL, apiKey, model string) {
// Run first compaction immediately on startup
if err := RunCompaction(ctx, client, config.KBCompactionInterval, config.KBCompactionSummarize, apiURL, apiKey, model); err != nil {
xlog.Warn("compaction ticker initial run failed", "collection", client.Collection(), "error", err)
}
interval := 24 * time.Hour
switch config.KBCompactionInterval {
case "weekly":
+17 -3
View File
@@ -97,9 +97,10 @@ type AgentConfig struct {
KnowledgeBaseResults int `json:"kb_results" form:"kb_results"`
CanStopItself bool `json:"can_stop_itself" form:"can_stop_itself"`
SystemPrompt string `json:"system_prompt" form:"system_prompt"`
LongTermMemory bool `json:"long_term_memory" form:"long_term_memory"`
SummaryLongTermMemory bool `json:"summary_long_term_memory" form:"summary_long_term_memory"`
ParallelJobs int `json:"parallel_jobs" form:"parallel_jobs"`
LongTermMemory bool `json:"long_term_memory" form:"long_term_memory"`
SummaryLongTermMemory bool `json:"summary_long_term_memory" form:"summary_long_term_memory"`
ConversationStorageMode string `json:"conversation_storage_mode" form:"conversation_storage_mode"`
ParallelJobs int `json:"parallel_jobs" form:"parallel_jobs"`
StripThinkingTags bool `json:"strip_thinking_tags" form:"strip_thinking_tags"`
EnableEvaluation bool `json:"enable_evaluation" form:"enable_evaluation"`
MaxEvaluationLoops int `json:"max_evaluation_loops" form:"max_evaluation_loops"`
@@ -299,6 +300,19 @@ func NewAgentConfigMeta(
HelpText: "Inject knowledge base search and add actions as tools, allowing the agent to access its memory without manual configuration",
Tags: config.Tags{Section: "MemorySettings"},
},
{
Name: "conversation_storage_mode",
Label: "Conversation Storage Mode",
Type: "select",
DefaultValue: "user_only",
Options: []config.FieldOption{
{Value: "user_only", Label: "User Messages Only"},
{Value: "user_and_assistant", Label: "User and Assistant Messages"},
{Value: "whole_conversation", Label: "Whole Conversation as Block"},
},
HelpText: "Controls what gets stored in the knowledge base: only user messages, user and assistant messages separately, or the entire conversation as a single block",
Tags: config.Tags{Section: "MemorySettings"},
},
{
Name: "system_prompt",
Label: "System Prompt",
+4 -8
View File
@@ -447,6 +447,10 @@ func (a *AgentPool) startAgentWithConfig(name, pooldir string, config *AgentConf
opts = append(opts, EnableSummaryMemory)
}
if config.ConversationStorageMode != "" {
opts = append(opts, WithConversationStorageMode(ConversationStorageMode(config.ConversationStorageMode)))
}
if config.CanStopItself {
opts = append(opts, CanStopItself)
}
@@ -479,14 +483,6 @@ func (a *AgentPool) startAgentWithConfig(name, pooldir string, config *AgentConf
if config.EnableKnowledgeBase {
ragClient = localrag.NewWrappedClient(a.localRAGAPI, a.localRAGKey, name)
opts = append(opts, WithRAGDB(ragClient), EnableKnowledgeBase)
if config.EnableKBCompaction {
interval := config.KBCompactionInterval
if interval == "" {
interval = "daily"
}
summarize := config.KBCompactionSummarize
opts = append(opts, EnableKBCompaction, WithKBCompactionInterval(interval), WithKBCompactionSummarize(summarize))
}
// Set KB auto search option (defaults to true for backward compatibility)
// For backward compatibility: if both new KB fields are false (zero values),
// assume this is an old config and default KBAutoSearch to true