Add user_profiles table to Memory.hs for per-user profile data.
Ava is designed to be multi-tenant (multiple users via Telegram). Currently:
users table exists with: id, telegram_id, email, name, created_atsettings table is GLOBAL (key/value, no user_id)We need a proper per-user profile system for:
-- Existing users table
CREATE TABLE users (
id TEXT PRIMARY KEY, -- UUID
telegram_id INTEGER UNIQUE, -- Telegram user ID
email TEXT,
name TEXT NOT NULL,
created_at TIMESTAMP
);
-- Existing settings table (GLOBAL, no user scope)
CREATE TABLE settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL,
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS user_profiles (
user_id TEXT PRIMARY KEY REFERENCES users(id),
display_name TEXT, -- What to call them
pronouns TEXT, -- he/him, she/her, they/them, etc.
timezone TEXT, -- America/New_York, etc.
tone_preference TEXT, -- terse, detailed, casual, formal
notes TEXT, -- Free-form notes about the user
updated_at TIMESTAMP NOT NULL,
-- Could add more structured fields:
-- locale TEXT, -- en-US, etc.
-- notification_hours TEXT, -- JSON: {"start": "09:00", "end": "22:00"}
);
-- Modify settings to include optional user_id
CREATE TABLE settings (
key TEXT NOT NULL,
user_id TEXT REFERENCES users(id), -- NULL = global setting
value TEXT NOT NULL,
updated_at TEXT NOT NULL,
PRIMARY KEY (key, user_id)
);
-- Then store as:
-- key: "profile.timezone", user_id: "uuid-123", value: "America/New_York"
-- key: "profile.pronouns", user_id: "uuid-123", value: "he/him"
Recommendation: Option A is cleaner for profile data. Option B is better if we want flexible per-user settings beyond just profile. Could do both.
Add after settings table creation:
-- User profiles table for per-user preferences
SQL.execute_
conn
"CREATE TABLE IF NOT EXISTS user_profiles (\
\ user_id TEXT PRIMARY KEY REFERENCES users(id),\
\ display_name TEXT,\
\ pronouns TEXT,\
\ timezone TEXT DEFAULT 'America/New_York',\
\ tone_preference TEXT DEFAULT 'terse',\
\ notes TEXT,\
\ updated_at TIMESTAMP NOT NULL\
\)"
data UserProfile = UserProfile
{ profileUserId :: Text
, profileDisplayName :: Maybe Text
, profilePronouns :: Maybe Text
, profileTimezone :: Text
, profileTonePreference :: Text
, profileNotes :: Maybe Text
, profileUpdatedAt :: UTCTime
}
deriving (Show, Eq, Generic)
instance Aeson.ToJSON UserProfile
instance Aeson.FromJSON UserProfile
instance SQL.FromRow UserProfile
instance SQL.ToRow UserProfile
-- | Get user profile, creating default if not exists
getUserProfile :: UserId -> IO UserProfile
-- | Update user profile (upsert)
updateUserProfile :: UserProfile -> IO ()
-- | Update a single profile field
setProfileField :: UserId -> Text -> Text -> IO ()
-- e.g., setProfileField uid "timezone" "America/Los_Angeles"
-- | Get profile field
getProfileField :: UserId -> Text -> IO (Maybe Text)
-- Tool: update_user_profile
-- Allows agent to update profile based on learned info
updateUserProfileTool :: UserId -> Engine.Tool
-- Tool schema:
-- { "field": "timezone", "value": "America/Los_Angeles" }
-- { "field": "notes", "value": "Prefers morning meetings, works on Omni" }
In the systemPrompt construction (~line 1555), add:
-- Load user profile
profile <- Memory.getUserProfile (Memory.UserId (Memory.unUserId uid))
let userSection =
"\n\n## User Profile\n"
<> "Name: " <> fromMaybe userName (profileDisplayName profile) <> "\n"
<> maybe "" (\p -> "Pronouns: " <> p <> "\n") (profilePronouns profile)
<> "Timezone: " <> profileTimezone profile <> "\n"
<> maybe "" (\n -> "Notes: " <> n <> "\n") (profileNotes profile)
On first access, create default profile from users table:
getUserProfile uid = do
existing <- queryProfile uid
case existing of
Just p -> pure p
Nothing -> do
user <- getUser uid
let defaultProfile = UserProfile
{ profileUserId = unUserId uid
, profileDisplayName = Just (userName user)
, profilePronouns = Nothing
, profileTimezone = "America/New_York"
, profileTonePreference = "terse"
, profileNotes = Nothing
, profileUpdatedAt = now
}
insertProfile defaultProfile
pure defaultProfile
1. Omni/Agent/Memory.hs
2. Omni/Ava/Telegram/Bot.hs
1. typecheck.sh Omni/Agent/Memory.hs
2. Add unit tests for UserProfile CRUD
3. Test profile appears in prompt
4. Test agent can update profile via tool
No activity yet.