Documentation
¶
Overview ¶
Package settings owns the settings a user changes while the daemon runs: the dry-run switch, the decision models and thresholds, retention, where trashed mail goes, whether the mailbox's own mail is left alone, and the model provider keys. They live in the settings table and lie over the environment (internal/config), which supplies the defaults. Provider keys are stored encrypted under the master key and are never handed back out of this package except inside the config the model adapters are built from.
Index ¶
- Constants
- Variables
- func CheckModel(spec string) string
- func KeyNames() []string
- type ComposerMissing
- type Invalid
- type Patch
- type Settings
- func (s *Settings) Apply(ctx context.Context, p Patch) error
- func (s *Settings) Composer(ctx context.Context) (models.Generator, error)
- func (s *Settings) Effective(ctx context.Context) (config.Config, error)
- func (s *Settings) Live(ctx context.Context) (router *models.Router, minConfidence float64)
- func (s *Settings) LookupWorkspaces(ctx context.Context) (WorkspaceLookup, error)
- func (s *Settings) RetentionDays(ctx context.Context) int
- func (s *Settings) RouterFor(ctx context.Context, spec string) *models.Router
- func (s *Settings) View(ctx context.Context) (View, error)
- type View
- type Warning
- type WorkspaceFinder
- type WorkspaceLookup
Constants ¶
const ( KeyStored = "stored" // saved through the API; it wins over the environment KeyEnvironment = "environment" // set in the daemon's environment only KeyNone = "none" )
Where a provider key in force comes from. Never the key.
const ( WorkspaceNoneNeeded = "none_needed" // the key was made for one workspace: nothing to name WorkspaceOne = "one" // one workspace, which MailRules stored as the setting WorkspaceSeveral = "several" // several: the user picks one WorkspaceFailed = "failed" // Anthropic could not say (no permission, network): the user types it )
What a lookup found out about the Claude key in force.
const DefaultRetentionDays = 30
DefaultRetentionDays is how long message snippets are kept until the user says otherwise.
Variables ¶
var Deciders = []string{"jev", "clef", "anthropic", "openai", "ollama"}
Deciders are the values MAILRULES_DECIDER accepts.
var ErrNoComposer = errors.New("no generative model is configured for the rule composer")
ErrNoComposer means no generative model is configured for the rule composer.
Functions ¶
func CheckModel ¶
CheckModel says, in a sentence, what is wrong with a rule's model override, or "" when it is a decider this daemon knows: empty (the default), a decider name, or name:model. openai and ollama have no default model.
Types ¶
type ComposerMissing ¶
type ComposerMissing struct {
Model string // composer_model as set, e.g. openai:gpt-4o-mini
Path string // the setting to fill in, as the API spells it
What string // what to call it, e.g. "an OpenAI API key"
}
ComposerMissing is ErrNoComposer with what the chosen composer model lacks: the one place that decides what the user is told to add.
func (*ComposerMissing) Error ¶
func (e *ComposerMissing) Error() string
func (*ComposerMissing) Is ¶
func (e *ComposerMissing) Is(target error) bool
Is makes errors.Is(err, ErrNoComposer) true.
func (*ComposerMissing) Message ¶
func (e *ComposerMissing) Message() string
Message is the sentence for a person: what the chosen model needs and where to add it.
type Invalid ¶
type Invalid struct{ Path, Message string }
Invalid is a settings change the user has to correct. Path names the field; Message is a sentence for a person, complete without the path.
type Patch ¶
type Patch struct {
Reset []string // setting names, as the API spells them
DryRun *bool
Decider *string
DeciderModel *string
FallbackModel *string
ComposerModel *string
EscalateBelow *float64
MinConfidence *float64
RetentionDays *int
TrashToFolder *bool
LeaveOwnMail *bool
OpenAIBaseURL *string // empty = api.openai.com
OllamaURL *string // empty = none
// AnthropicWorkspaceID is empty or a wrkspc_ ID (config.ValidWorkspaceID); empty = none.
AnthropicWorkspaceID *string
Keys map[string]string
}
Patch is a change: nil fields stay as they are. An empty string is a value like any other, stored as it is: no fallback, the provider's default model, no URL. Where an empty value cannot work (the composer's model, the model of a decider that has no default) it is refused. Reset names the settings to forget, which puts the environment's default back in force. In Keys, an empty value removes the stored key: a key cannot be "set to nothing".
type Settings ¶
type Settings struct {
Store *store.Store
Master []byte
Env *config.Config // the defaults
Deps models.Deps // shared by every router built here
// Workspaces looks up the workspace a Claude key needs; nil = never looked up, the
// user types it.
Workspaces WorkspaceFinder
// contains filtered or unexported fields
}
Settings reads and changes the stored settings.
func (*Settings) Apply ¶
Apply validates a change against the settings it would produce and stores it in one transaction. A problem the user can fix comes back as *Invalid. Nothing needs a restart: the executor reads dry-run and trash_to_folder before every action, the pipeline reads leave_own_mail for every email, and Live rebuilds the router. A Claude key saved or replaced forgets what was learnt about the old one's workspace, and a workspace MailRules found for it; then, with no workspace set, it is looked up.
func (*Settings) Composer ¶
Composer returns the generative model the rule composer writes rules with: composer_model as config.SplitComposerModel reads it, on Anthropic, an OpenAI-compatible endpoint or Ollama. Until that provider has its key or URL it is a *ComposerMissing, which is ErrNoComposer.
func (*Settings) Effective ¶
Effective returns the configuration in force: the environment with the stored settings laid over it. It holds decrypted provider keys, so it is for building model adapters, never for showing.
func (*Settings) Live ¶
Live returns the decision router and the act threshold for the settings as stored right now; pipeline.Pipeline.Live is this method. The router is rebuilt only when a stored setting has changed since the last call, whoever changed it, so a save in the browser reaches the next email without a restart. router is nil while the decider lacks its key.
func (*Settings) LookupWorkspaces ¶
func (s *Settings) LookupWorkspaces(ctx context.Context) (WorkspaceLookup, error)
LookupWorkspaces says which workspace the Claude key in force needs, as the Settings screen asks. A known answer (none needed, one, several) is given again without asking Anthropic; otherwise Anthropic is asked, and one workspace found while none is set is stored as the setting.
func (*Settings) RetentionDays ¶
RetentionDays returns the retention_days setting in force: how long message snippets are kept. When the settings cannot be read it is the default.
func (*Settings) RouterFor ¶
RouterFor returns the router for a rule's model override (a decider spec, see CheckModel), built from the settings in force and kept until they change. It is nil when that decider cannot be used, for example because its key is not set; the caller then decides with the default router. pipeline.Pipeline.Override is this method.
type View ¶
type View struct {
DryRun bool
Decider string
DeciderModel string
FallbackModel string // empty = never escalate
ComposerModel string
EscalateBelow float64
MinConfidence float64
RetentionDays int
TrashToFolder bool // trash goes to actions.TrashFolder, not the server's Trash
LeaveOwnMail bool // mail from the mailbox's own address is left alone (pipeline.OwnMail)
OpenAIBaseURL string // an OpenAI-compatible endpoint; empty = api.openai.com
OllamaURL string // a local Ollama server
Keys map[string]string // KeyStored | KeyEnvironment | KeyNone
Warnings []Warning // never nil
// The Claude workspace every Claude request names; empty = none. Its name is known when
// a lookup listed it; Found says MailRules looked it up and stored it itself.
AnthropicWorkspaceID string
AnthropicWorkspaceName string
AnthropicWorkspaceFound bool
}
View is what may be shown: every setting in force, and for each provider key only where it comes from.
type Warning ¶
type Warning struct {
Code string `json:"code"`
Message string `json:"message"`
Path string `json:"path"`
}
Warning is something about the settings in force that will not work as it stands, which the user may still be on the way to fixing (the first-run wizard saves in steps), so it is reported and not refused. Path names the setting to fill in.
type WorkspaceFinder ¶
type WorkspaceFinder interface {
Find(ctx context.Context, apiKey string) (models.WorkspaceAnswer, error)
}
WorkspaceFinder asks Anthropic which workspace a Claude key needs. models.AnthropicWorkspaces is the one the daemon uses.
type WorkspaceLookup ¶
WorkspaceLookup is what a lookup answers: its status and, for one or several, the organisation's workspaces (never nil).