package config import "time" // Two loops that run behind the conversation and never speak. Both are absent // by default, and both follow the same rule as every other cost the owner did // not ask for: present-but-empty (`{}`) is a valid "on with the defaults". // MemoryEvalConfig — the background memory-evaluation loop (Vikunja #248). // Absent ⇒ off, like every other capability that costs something the owner did // not ask for. Each evaluation is a full LLM round-trip on the one resident // model, which is the same model answering him; running it hourly by default // would put a multi-second stall in front of an occasional voice turn for a // feature he may not want. // // The loop only ever writes notes (source infer:memory-eval, visible on // /dash). It cannot speak — see internal/memeval. type MemoryEvalConfig struct { // Interval — how often to evaluate. 0 ⇒ DefaultMemoryEvalInterval. Interval Duration `json:"interval,omitempty"` // MaxItems — recent facts / notes / nudges fed into one evaluation. // 0 ⇒ memeval.DefaultMaxItems. MaxItems int `json:"max_items,omitempty"` // MinConfidence — observations the model scores below this are dropped. // 0 ⇒ memeval.DefaultMinConfidence. MinConfidence float64 `json:"min_confidence,omitempty"` } // DefaultMemoryEvalInterval — the plan's cadence (1h) for the memory // evaluation loop, applied only when the block is present at all. const DefaultMemoryEvalInterval = time.Hour // normaliseMemoryEval leaves an absent block nil (⇒ no evaluation loop) and // gives a present one the plan's cadence. func (c *Config) normaliseMemoryEval() { if c.MemoryEval != nil && c.MemoryEval.Interval <= 0 { c.MemoryEval.Interval = Duration(DefaultMemoryEvalInterval) } } // EmailConfig — core's half of the email reader: how many task candidates one // message may produce, and how long the extraction call may take. // // There is deliberately nothing about a mailbox here. Core does not connect to // IMAP, does not know an account exists, and holds no mail credential — the // reader daemon does, the same split mavpoll uses for the zenmoney token. This // block only says "extraction is allowed, with these bounds". type EmailConfig struct { // MaxTasks — candidates per message. 0 ⇒ email.MaxCandidates (3). MaxTasks int `json:"max_tasks,omitempty"` // Timeout — per-message extraction budget. 0 ⇒ DefaultEmailTimeout. This is // a Thinking model reading a mail; nobody is waiting on the answer, but a // hung llama-server must not pin the reader's connection forever. Timeout Duration `json:"timeout,omitempty"` } // DefaultEmailTimeout — extraction budget per message. const DefaultEmailTimeout = 2 * time.Minute // normaliseEmail leaves an absent block nil (⇒ mail ingestion refused) and // gives a present one the timeout default. func (c *Config) normaliseEmail() { if c.Email != nil && c.Email.Timeout <= 0 { c.Email.Timeout = Duration(DefaultEmailTimeout) } }