-- name: CreateMessage :one INSERT INTO bot_history_messages ( bot_id, session_id, sender_channel_identity_id, sender_account_user_id, source_message_id, source_reply_to_message_id, role, content, metadata, usage, model_id ) VALUES ( sqlc.arg(bot_id), sqlc.narg(session_id)::uuid, sqlc.narg(sender_channel_identity_id)::uuid, sqlc.narg(sender_user_id)::uuid, sqlc.narg(external_message_id)::text, sqlc.narg(source_reply_to_message_id)::text, sqlc.arg(role), sqlc.arg(content), sqlc.arg(metadata), sqlc.arg(usage), sqlc.narg(model_id)::uuid ) RETURNING id, bot_id, session_id, sender_channel_identity_id, sender_account_user_id AS sender_user_id, source_message_id AS external_message_id, source_reply_to_message_id, role, content, metadata, usage, created_at; -- name: ListMessages :many SELECT m.id, m.bot_id, m.session_id, m.sender_channel_identity_id, m.sender_account_user_id AS sender_user_id, m.source_message_id AS external_message_id, m.source_reply_to_message_id, m.role, m.content, m.metadata, m.usage, m.created_at, ci.display_name AS sender_display_name, ci.avatar_url AS sender_avatar_url, s.channel_type AS platform FROM bot_history_messages m LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id LEFT JOIN bot_sessions s ON s.id = m.session_id WHERE m.bot_id = sqlc.arg(bot_id) ORDER BY m.created_at ASC LIMIT 10000; -- name: ListMessagesBySession :many SELECT m.id, m.bot_id, m.session_id, m.sender_channel_identity_id, m.sender_account_user_id AS sender_user_id, m.source_message_id AS external_message_id, m.source_reply_to_message_id, m.role, m.content, m.metadata, m.usage, m.created_at, ci.display_name AS sender_display_name, ci.avatar_url AS sender_avatar_url, s.channel_type AS platform FROM bot_history_messages m LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id LEFT JOIN bot_sessions s ON s.id = m.session_id WHERE m.session_id = sqlc.arg(session_id) ORDER BY m.created_at ASC LIMIT 10000; -- name: ListMessagesSince :many SELECT m.id, m.bot_id, m.session_id, m.sender_channel_identity_id, m.sender_account_user_id AS sender_user_id, m.source_message_id AS external_message_id, m.source_reply_to_message_id, m.role, m.content, m.metadata, m.usage, m.created_at, ci.display_name AS sender_display_name, ci.avatar_url AS sender_avatar_url, s.channel_type AS platform FROM bot_history_messages m LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id LEFT JOIN bot_sessions s ON s.id = m.session_id WHERE m.bot_id = sqlc.arg(bot_id) AND m.created_at >= sqlc.arg(created_at) ORDER BY m.created_at ASC; -- name: ListMessagesSinceBySession :many SELECT m.id, m.bot_id, m.session_id, m.sender_channel_identity_id, m.sender_account_user_id AS sender_user_id, m.source_message_id AS external_message_id, m.source_reply_to_message_id, m.role, m.content, m.metadata, m.usage, m.created_at, ci.display_name AS sender_display_name, ci.avatar_url AS sender_avatar_url, s.channel_type AS platform FROM bot_history_messages m LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id LEFT JOIN bot_sessions s ON s.id = m.session_id WHERE m.session_id = sqlc.arg(session_id) AND m.created_at >= sqlc.arg(created_at) ORDER BY m.created_at ASC; -- name: ListActiveMessagesSince :many SELECT m.id, m.bot_id, m.session_id, m.sender_channel_identity_id, m.sender_account_user_id AS sender_user_id, m.source_message_id AS external_message_id, m.source_reply_to_message_id, m.role, m.content, m.metadata, m.usage, m.compact_id, m.created_at, ci.display_name AS sender_display_name, ci.avatar_url AS sender_avatar_url, s.channel_type AS platform FROM bot_history_messages m LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id LEFT JOIN bot_sessions s ON s.id = m.session_id WHERE m.bot_id = sqlc.arg(bot_id) AND m.created_at >= sqlc.arg(created_at) AND (m.metadata->>'trigger_mode' IS NULL OR m.metadata->>'trigger_mode' != 'passive_sync') ORDER BY m.created_at ASC; -- name: ListActiveMessagesSinceBySession :many SELECT m.id, m.bot_id, m.session_id, m.sender_channel_identity_id, m.sender_account_user_id AS sender_user_id, m.source_message_id AS external_message_id, m.source_reply_to_message_id, m.role, m.content, m.metadata, m.usage, m.compact_id, m.created_at, ci.display_name AS sender_display_name, ci.avatar_url AS sender_avatar_url, s.channel_type AS platform FROM bot_history_messages m LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id LEFT JOIN bot_sessions s ON s.id = m.session_id WHERE m.session_id = sqlc.arg(session_id) AND m.created_at >= sqlc.arg(created_at) AND (m.metadata->>'trigger_mode' IS NULL OR m.metadata->>'trigger_mode' != 'passive_sync') ORDER BY m.created_at ASC; -- name: ListMessagesBefore :many SELECT m.id, m.bot_id, m.session_id, m.sender_channel_identity_id, m.sender_account_user_id AS sender_user_id, m.source_message_id AS external_message_id, m.source_reply_to_message_id, m.role, m.content, m.metadata, m.usage, m.created_at, ci.display_name AS sender_display_name, ci.avatar_url AS sender_avatar_url, s.channel_type AS platform FROM bot_history_messages m LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id LEFT JOIN bot_sessions s ON s.id = m.session_id WHERE m.bot_id = sqlc.arg(bot_id) AND m.created_at < sqlc.arg(created_at) ORDER BY m.created_at DESC LIMIT sqlc.arg(max_count); -- name: ListMessagesBeforeBySession :many SELECT m.id, m.bot_id, m.session_id, m.sender_channel_identity_id, m.sender_account_user_id AS sender_user_id, m.source_message_id AS external_message_id, m.source_reply_to_message_id, m.role, m.content, m.metadata, m.usage, m.created_at, ci.display_name AS sender_display_name, ci.avatar_url AS sender_avatar_url, s.channel_type AS platform FROM bot_history_messages m LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id LEFT JOIN bot_sessions s ON s.id = m.session_id WHERE m.session_id = sqlc.arg(session_id) AND m.created_at < sqlc.arg(created_at) ORDER BY m.created_at DESC LIMIT sqlc.arg(max_count); -- name: ListMessagesLatest :many SELECT m.id, m.bot_id, m.session_id, m.sender_channel_identity_id, m.sender_account_user_id AS sender_user_id, m.source_message_id AS external_message_id, m.source_reply_to_message_id, m.role, m.content, m.metadata, m.usage, m.created_at, ci.display_name AS sender_display_name, ci.avatar_url AS sender_avatar_url, s.channel_type AS platform FROM bot_history_messages m LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id LEFT JOIN bot_sessions s ON s.id = m.session_id WHERE m.bot_id = sqlc.arg(bot_id) ORDER BY m.created_at DESC LIMIT sqlc.arg(max_count); -- name: ListMessagesLatestBySession :many SELECT m.id, m.bot_id, m.session_id, m.sender_channel_identity_id, m.sender_account_user_id AS sender_user_id, m.source_message_id AS external_message_id, m.source_reply_to_message_id, m.role, m.content, m.metadata, m.usage, m.created_at, ci.display_name AS sender_display_name, ci.avatar_url AS sender_avatar_url, s.channel_type AS platform FROM bot_history_messages m LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id LEFT JOIN bot_sessions s ON s.id = m.session_id WHERE m.session_id = sqlc.arg(session_id) ORDER BY m.created_at DESC LIMIT sqlc.arg(max_count); -- name: DeleteMessagesByBot :exec DELETE FROM bot_history_messages WHERE bot_id = sqlc.arg(bot_id); -- name: DeleteMessagesBySession :exec DELETE FROM bot_history_messages WHERE session_id = sqlc.arg(session_id); -- name: ListObservedConversationsByChannelIdentity :many WITH observed_routes AS ( SELECT s.route_id, MAX(m.created_at)::timestamptz AS last_observed_at FROM bot_history_messages m JOIN bot_sessions s ON s.id = m.session_id WHERE m.bot_id = sqlc.arg(bot_id) AND m.sender_channel_identity_id = sqlc.arg(channel_identity_id)::uuid AND s.route_id IS NOT NULL GROUP BY s.route_id ) SELECT r.id AS route_id, r.channel_type AS channel, CASE WHEN LOWER(COALESCE(r.conversation_type, '')) IN ('thread', 'topic') THEN 'thread' WHEN LOWER(COALESCE(r.conversation_type, '')) IN ('p2p', 'private', 'direct', 'dm') THEN 'private' ELSE 'group' END AS conversation_type, r.external_conversation_id AS conversation_id, COALESCE(r.external_thread_id, '') AS thread_id, COALESCE( NULLIF(TRIM(COALESCE(r.metadata->>'conversation_name', '')), ''), NULLIF(TRIM(COALESCE(r.metadata->>'conversation_handle', '')), ''), '' )::text AS conversation_name, rr.last_observed_at FROM observed_routes rr JOIN bot_channel_routes r ON r.id = rr.route_id GROUP BY r.id, r.channel_type, r.conversation_type, r.external_conversation_id, r.external_thread_id, r.metadata, rr.last_observed_at ORDER BY rr.last_observed_at DESC; -- name: ListObservedConversationsByChannelType :many -- Routes on this platform type where the bot has seen at least one message (any sender). WITH observed_routes AS ( SELECT s.route_id, MAX(m.created_at)::timestamptz AS last_observed_at FROM bot_history_messages m JOIN bot_sessions s ON s.id = m.session_id JOIN bot_channel_routes r ON r.id = s.route_id WHERE m.bot_id = sqlc.arg(bot_id) AND LOWER(TRIM(r.channel_type)) = LOWER(TRIM(sqlc.arg(channel_type))) AND s.route_id IS NOT NULL GROUP BY s.route_id ) SELECT r.id AS route_id, r.channel_type AS channel, CASE WHEN LOWER(COALESCE(r.conversation_type, '')) IN ('thread', 'topic') THEN 'thread' WHEN LOWER(COALESCE(r.conversation_type, '')) IN ('p2p', 'private', 'direct', 'dm') THEN 'private' ELSE 'group' END AS conversation_type, r.external_conversation_id AS conversation_id, COALESCE(r.external_thread_id, '') AS thread_id, COALESCE( NULLIF(TRIM(COALESCE(r.metadata->>'conversation_name', '')), ''), NULLIF(TRIM(COALESCE(r.metadata->>'conversation_handle', '')), ''), '' )::text AS conversation_name, rr.last_observed_at FROM observed_routes rr JOIN bot_channel_routes r ON r.id = rr.route_id GROUP BY r.id, r.channel_type, r.conversation_type, r.external_conversation_id, r.external_thread_id, r.metadata, rr.last_observed_at ORDER BY rr.last_observed_at DESC; -- name: SearchMessages :many SELECT m.id, m.bot_id, m.session_id, m.sender_channel_identity_id, m.role, m.content, m.created_at, ci.display_name AS sender_display_name, s.channel_type AS platform FROM bot_history_messages m LEFT JOIN channel_identities ci ON ci.id = m.sender_channel_identity_id LEFT JOIN bot_sessions s ON s.id = m.session_id WHERE m.bot_id = sqlc.arg(bot_id) AND (sqlc.narg(session_id)::uuid IS NULL OR m.session_id = sqlc.narg(session_id)::uuid) AND (sqlc.narg(contact_id)::uuid IS NULL OR m.sender_channel_identity_id = sqlc.narg(contact_id)::uuid) AND (sqlc.narg(start_time)::timestamptz IS NULL OR m.created_at >= sqlc.narg(start_time)::timestamptz) AND (sqlc.narg(end_time)::timestamptz IS NULL OR m.created_at <= sqlc.narg(end_time)::timestamptz) AND (sqlc.narg(role)::text IS NULL OR m.role = sqlc.narg(role)::text) AND (sqlc.narg(keyword)::text IS NULL OR ( CASE WHEN jsonb_typeof(m.content->'content') = 'string' THEN m.content->>'content' WHEN jsonb_typeof(m.content->'content') = 'array' THEN (SELECT COALESCE(string_agg(elem->>'text', ' '), '') FROM jsonb_array_elements(m.content->'content') AS elem WHERE elem->>'type' = 'text') ELSE '' END ) ILIKE '%' || sqlc.narg(keyword)::text || '%') ORDER BY m.created_at DESC LIMIT sqlc.arg(max_count); -- name: MarkMessagesCompacted :exec UPDATE bot_history_messages SET compact_id = $1 WHERE id = ANY($2::uuid[]); -- name: ListUncompactedMessagesBySession :many SELECT id, bot_id, session_id, role, content, usage, sender_channel_identity_id, compact_id, created_at FROM bot_history_messages WHERE session_id = $1 AND compact_id IS NULL ORDER BY created_at ASC;