Files
MealQuest/internal/household/defaults.go
T
dev_agentandClaude Opus 5.5 989d13b69c
CI / ci (pull_request) Successful in 1m24s
Independent review Codex gpt-6-sol high: APPROVED (0 findings)
CI / ci (push) Successful in 1m26s
Seed default AI settings and notification preferences at boot
On first boot create the ai_settings row (provider anthropic, empty base
URL, model and key, temperature 0.7, system prompt DefaultPersonaPrompt
from CTXD PROMPTS.MD §4) and a notification_prefs row per event (push on
for all five, chat on for plan_ready and list_ready only). Existing rows
are never changed; a missing event row is seeded on its own.

cmd/server seeds household settings, AI settings and notification
preferences through seedDefaults; any failure stops the boot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 14:54:58 -04:00

94 lines
3.2 KiB
Go

package household
import (
"context"
"database/sql"
"errors"
"fmt"
"code.cubecraftlabs.com/Maniacs_Mansion/Meal-Quest/internal/db"
"code.cubecraftlabs.com/Maniacs_Mansion/Meal-Quest/internal/store"
)
// DefaultPersonaPrompt is the default AI system prompt (CTXD PROMPTS.MD §4).
// SeedAISettings stores it on first boot and the Admin reset restores it.
const DefaultPersonaPrompt = `You are MealQuest, a dinner planning assistant for one household. Suggest dinners
similar to their regular rotation, nudging them to try something a little new each
week. Prefer weeknight-friendly recipes with common grocery-store ingredients.
Flag crock pot meals and anything 30 minutes or less as "quick". Keep explanations
short, warm and specific — mention the household's own regular dinners when you
explain why something fits. Never suggest a dinner they already make or have
declined.`
// Seed values for the AI settings (CTXD CONTEXT.MD). The base URL and model
// are empty until the household picks a provider preset; there is no key.
const (
SeedAIProvider = "anthropic"
SeedAIBaseURL = ""
SeedAIModel = ""
SeedAITemperature = 0.7
)
// seedNotificationPrefs are the notification preferences for a new
// household, one per event: push for every event, chat only for the plan
// and the shopping list.
var seedNotificationPrefs = []struct {
Event string
Push, Chat bool
}{
{Event: "plan_ready", Push: true, Chat: true},
{Event: "list_ready", Push: true, Chat: true},
{Event: "day_of_reminder", Push: true, Chat: false},
{Event: "new_suggestions", Push: true, Chat: false},
{Event: "rotation_review", Push: true, Chat: false},
}
// SeedAISettings creates the AI settings row with the seed values and
// DefaultPersonaPrompt if it does not exist. An existing row is never
// changed.
func SeedAISettings(ctx context.Context, st *store.Store) error {
return st.WithTx(ctx, func(tx *sql.Tx) error {
q := db.New(tx)
_, err := q.GetAISettings(ctx)
if err == nil {
return nil
}
if !errors.Is(err, sql.ErrNoRows) {
return fmt.Errorf("household: read AI settings: %w", err)
}
now := store.Now().String()
_, err = q.UpsertAISettings(ctx, db.UpsertAISettingsParams{
Provider: SeedAIProvider,
BaseUrl: SeedAIBaseURL,
Model: SeedAIModel,
Temperature: SeedAITemperature,
SystemPrompt: sql.NullString{String: DefaultPersonaPrompt, Valid: true},
CreatedAt: now,
UpdatedAt: now,
})
if err != nil {
return fmt.Errorf("household: seed AI settings: %w", err)
}
return nil
})
}
// SeedNotificationPrefs creates the seed notification preference row of
// every event that has none. Existing rows are never changed.
func SeedNotificationPrefs(ctx context.Context, st *store.Store) error {
return st.WithTx(ctx, func(tx *sql.Tx) error {
now := store.Now().String()
for _, p := range seedNotificationPrefs {
_, err := tx.ExecContext(ctx,
`INSERT INTO notification_prefs (event, push, chat, created_at, updated_at)
VALUES (?, ?, ?, ?, ?)
ON CONFLICT (event) DO NOTHING`,
p.Event, p.Push, p.Chat, now, now)
if err != nil {
return fmt.Errorf("household: seed notification preference %s: %w", p.Event, err)
}
}
return nil
})
}