Files
Memoh/internal/db/sqlc/messages.sql.go
T
Acbox Liu b88ca96064 refactor: provider & models (#277)
* refactor: move client_type to provider, replace model fields with config JSONB

- Move `client_type` from `models` to `llm_providers` table
- Add `icon` field to `llm_providers`
- Replace `dimensions`, `input_modalities`, `supports_reasoning` on `models`
  with a single `config` JSONB column containing `dimensions`,
  `compatibilities` (vision, tool-call, image-output, reasoning),
  and `context_window`
- Auto-imported models default to vision + tool-call + reasoning
- Update all backend consumers (agent, flow resolver, handlers, memory)
- Regenerate sqlc, swagger, and TypeScript SDK
- Update frontend forms, display, and i18n for new schema

* ui: show provider icon avatar in sidebar and detail header, remove icon input

* feat: add built-in provider registry with YAML definitions and enable toggle

- Add `enable` column to llm_providers (default true, backward-compatible)
- Create internal/registry package to load YAML provider/model definitions
  on startup and upsert into database (new providers disabled by default)
- Add conf/providers/ with OpenAI, Anthropic, Google YAML definitions
- Add RegistryConfig to TOML config (providers_dir, default conf/providers)
- Model listing APIs and conversation flow now filter by enabled providers
- Frontend: enable switch in provider form, green status dot in sidebar,
  enabled providers sorted to top

* fix: make 0041 migration idempotent for fresh databases

Guard data migration steps with column-existence checks so the
migration succeeds on databases created from the updated init schema.
2026-03-22 17:24:45 +08:00

1221 lines
37 KiB
Go

// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.30.0
// source: messages.sql
package sqlc
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const createMessage = `-- 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 (
$1,
$2::uuid,
$3::uuid,
$4::uuid,
$5::text,
$6::text,
$7,
$8,
$9,
$10,
$11::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
`
type CreateMessageParams struct {
BotID pgtype.UUID `json:"bot_id"`
SessionID pgtype.UUID `json:"session_id"`
SenderChannelIdentityID pgtype.UUID `json:"sender_channel_identity_id"`
SenderUserID pgtype.UUID `json:"sender_user_id"`
ExternalMessageID pgtype.Text `json:"external_message_id"`
SourceReplyToMessageID pgtype.Text `json:"source_reply_to_message_id"`
Role string `json:"role"`
Content []byte `json:"content"`
Metadata []byte `json:"metadata"`
Usage []byte `json:"usage"`
ModelID pgtype.UUID `json:"model_id"`
}
type CreateMessageRow struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
SessionID pgtype.UUID `json:"session_id"`
SenderChannelIdentityID pgtype.UUID `json:"sender_channel_identity_id"`
SenderUserID pgtype.UUID `json:"sender_user_id"`
ExternalMessageID pgtype.Text `json:"external_message_id"`
SourceReplyToMessageID pgtype.Text `json:"source_reply_to_message_id"`
Role string `json:"role"`
Content []byte `json:"content"`
Metadata []byte `json:"metadata"`
Usage []byte `json:"usage"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
func (q *Queries) CreateMessage(ctx context.Context, arg CreateMessageParams) (CreateMessageRow, error) {
row := q.db.QueryRow(ctx, createMessage,
arg.BotID,
arg.SessionID,
arg.SenderChannelIdentityID,
arg.SenderUserID,
arg.ExternalMessageID,
arg.SourceReplyToMessageID,
arg.Role,
arg.Content,
arg.Metadata,
arg.Usage,
arg.ModelID,
)
var i CreateMessageRow
err := row.Scan(
&i.ID,
&i.BotID,
&i.SessionID,
&i.SenderChannelIdentityID,
&i.SenderUserID,
&i.ExternalMessageID,
&i.SourceReplyToMessageID,
&i.Role,
&i.Content,
&i.Metadata,
&i.Usage,
&i.CreatedAt,
)
return i, err
}
const deleteMessagesByBot = `-- name: DeleteMessagesByBot :exec
DELETE FROM bot_history_messages
WHERE bot_id = $1
`
func (q *Queries) DeleteMessagesByBot(ctx context.Context, botID pgtype.UUID) error {
_, err := q.db.Exec(ctx, deleteMessagesByBot, botID)
return err
}
const deleteMessagesBySession = `-- name: DeleteMessagesBySession :exec
DELETE FROM bot_history_messages
WHERE session_id = $1
`
func (q *Queries) DeleteMessagesBySession(ctx context.Context, sessionID pgtype.UUID) error {
_, err := q.db.Exec(ctx, deleteMessagesBySession, sessionID)
return err
}
const listActiveMessagesSince = `-- 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 = $1
AND m.created_at >= $2
AND (m.metadata->>'trigger_mode' IS NULL OR m.metadata->>'trigger_mode' != 'passive_sync')
ORDER BY m.created_at ASC
`
type ListActiveMessagesSinceParams struct {
BotID pgtype.UUID `json:"bot_id"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
type ListActiveMessagesSinceRow struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
SessionID pgtype.UUID `json:"session_id"`
SenderChannelIdentityID pgtype.UUID `json:"sender_channel_identity_id"`
SenderUserID pgtype.UUID `json:"sender_user_id"`
ExternalMessageID pgtype.Text `json:"external_message_id"`
SourceReplyToMessageID pgtype.Text `json:"source_reply_to_message_id"`
Role string `json:"role"`
Content []byte `json:"content"`
Metadata []byte `json:"metadata"`
Usage []byte `json:"usage"`
CompactID pgtype.UUID `json:"compact_id"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
SenderDisplayName pgtype.Text `json:"sender_display_name"`
SenderAvatarUrl pgtype.Text `json:"sender_avatar_url"`
Platform pgtype.Text `json:"platform"`
}
func (q *Queries) ListActiveMessagesSince(ctx context.Context, arg ListActiveMessagesSinceParams) ([]ListActiveMessagesSinceRow, error) {
rows, err := q.db.Query(ctx, listActiveMessagesSince, arg.BotID, arg.CreatedAt)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListActiveMessagesSinceRow
for rows.Next() {
var i ListActiveMessagesSinceRow
if err := rows.Scan(
&i.ID,
&i.BotID,
&i.SessionID,
&i.SenderChannelIdentityID,
&i.SenderUserID,
&i.ExternalMessageID,
&i.SourceReplyToMessageID,
&i.Role,
&i.Content,
&i.Metadata,
&i.Usage,
&i.CompactID,
&i.CreatedAt,
&i.SenderDisplayName,
&i.SenderAvatarUrl,
&i.Platform,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listActiveMessagesSinceBySession = `-- 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 = $1
AND m.created_at >= $2
AND (m.metadata->>'trigger_mode' IS NULL OR m.metadata->>'trigger_mode' != 'passive_sync')
ORDER BY m.created_at ASC
`
type ListActiveMessagesSinceBySessionParams struct {
SessionID pgtype.UUID `json:"session_id"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
type ListActiveMessagesSinceBySessionRow struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
SessionID pgtype.UUID `json:"session_id"`
SenderChannelIdentityID pgtype.UUID `json:"sender_channel_identity_id"`
SenderUserID pgtype.UUID `json:"sender_user_id"`
ExternalMessageID pgtype.Text `json:"external_message_id"`
SourceReplyToMessageID pgtype.Text `json:"source_reply_to_message_id"`
Role string `json:"role"`
Content []byte `json:"content"`
Metadata []byte `json:"metadata"`
Usage []byte `json:"usage"`
CompactID pgtype.UUID `json:"compact_id"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
SenderDisplayName pgtype.Text `json:"sender_display_name"`
SenderAvatarUrl pgtype.Text `json:"sender_avatar_url"`
Platform pgtype.Text `json:"platform"`
}
func (q *Queries) ListActiveMessagesSinceBySession(ctx context.Context, arg ListActiveMessagesSinceBySessionParams) ([]ListActiveMessagesSinceBySessionRow, error) {
rows, err := q.db.Query(ctx, listActiveMessagesSinceBySession, arg.SessionID, arg.CreatedAt)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListActiveMessagesSinceBySessionRow
for rows.Next() {
var i ListActiveMessagesSinceBySessionRow
if err := rows.Scan(
&i.ID,
&i.BotID,
&i.SessionID,
&i.SenderChannelIdentityID,
&i.SenderUserID,
&i.ExternalMessageID,
&i.SourceReplyToMessageID,
&i.Role,
&i.Content,
&i.Metadata,
&i.Usage,
&i.CompactID,
&i.CreatedAt,
&i.SenderDisplayName,
&i.SenderAvatarUrl,
&i.Platform,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listMessages = `-- 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 = $1
ORDER BY m.created_at ASC
LIMIT 10000
`
type ListMessagesRow struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
SessionID pgtype.UUID `json:"session_id"`
SenderChannelIdentityID pgtype.UUID `json:"sender_channel_identity_id"`
SenderUserID pgtype.UUID `json:"sender_user_id"`
ExternalMessageID pgtype.Text `json:"external_message_id"`
SourceReplyToMessageID pgtype.Text `json:"source_reply_to_message_id"`
Role string `json:"role"`
Content []byte `json:"content"`
Metadata []byte `json:"metadata"`
Usage []byte `json:"usage"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
SenderDisplayName pgtype.Text `json:"sender_display_name"`
SenderAvatarUrl pgtype.Text `json:"sender_avatar_url"`
Platform pgtype.Text `json:"platform"`
}
func (q *Queries) ListMessages(ctx context.Context, botID pgtype.UUID) ([]ListMessagesRow, error) {
rows, err := q.db.Query(ctx, listMessages, botID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListMessagesRow
for rows.Next() {
var i ListMessagesRow
if err := rows.Scan(
&i.ID,
&i.BotID,
&i.SessionID,
&i.SenderChannelIdentityID,
&i.SenderUserID,
&i.ExternalMessageID,
&i.SourceReplyToMessageID,
&i.Role,
&i.Content,
&i.Metadata,
&i.Usage,
&i.CreatedAt,
&i.SenderDisplayName,
&i.SenderAvatarUrl,
&i.Platform,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listMessagesBefore = `-- 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 = $1
AND m.created_at < $2
ORDER BY m.created_at DESC
LIMIT $3
`
type ListMessagesBeforeParams struct {
BotID pgtype.UUID `json:"bot_id"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
MaxCount int32 `json:"max_count"`
}
type ListMessagesBeforeRow struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
SessionID pgtype.UUID `json:"session_id"`
SenderChannelIdentityID pgtype.UUID `json:"sender_channel_identity_id"`
SenderUserID pgtype.UUID `json:"sender_user_id"`
ExternalMessageID pgtype.Text `json:"external_message_id"`
SourceReplyToMessageID pgtype.Text `json:"source_reply_to_message_id"`
Role string `json:"role"`
Content []byte `json:"content"`
Metadata []byte `json:"metadata"`
Usage []byte `json:"usage"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
SenderDisplayName pgtype.Text `json:"sender_display_name"`
SenderAvatarUrl pgtype.Text `json:"sender_avatar_url"`
Platform pgtype.Text `json:"platform"`
}
func (q *Queries) ListMessagesBefore(ctx context.Context, arg ListMessagesBeforeParams) ([]ListMessagesBeforeRow, error) {
rows, err := q.db.Query(ctx, listMessagesBefore, arg.BotID, arg.CreatedAt, arg.MaxCount)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListMessagesBeforeRow
for rows.Next() {
var i ListMessagesBeforeRow
if err := rows.Scan(
&i.ID,
&i.BotID,
&i.SessionID,
&i.SenderChannelIdentityID,
&i.SenderUserID,
&i.ExternalMessageID,
&i.SourceReplyToMessageID,
&i.Role,
&i.Content,
&i.Metadata,
&i.Usage,
&i.CreatedAt,
&i.SenderDisplayName,
&i.SenderAvatarUrl,
&i.Platform,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listMessagesBeforeBySession = `-- 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 = $1
AND m.created_at < $2
ORDER BY m.created_at DESC
LIMIT $3
`
type ListMessagesBeforeBySessionParams struct {
SessionID pgtype.UUID `json:"session_id"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
MaxCount int32 `json:"max_count"`
}
type ListMessagesBeforeBySessionRow struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
SessionID pgtype.UUID `json:"session_id"`
SenderChannelIdentityID pgtype.UUID `json:"sender_channel_identity_id"`
SenderUserID pgtype.UUID `json:"sender_user_id"`
ExternalMessageID pgtype.Text `json:"external_message_id"`
SourceReplyToMessageID pgtype.Text `json:"source_reply_to_message_id"`
Role string `json:"role"`
Content []byte `json:"content"`
Metadata []byte `json:"metadata"`
Usage []byte `json:"usage"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
SenderDisplayName pgtype.Text `json:"sender_display_name"`
SenderAvatarUrl pgtype.Text `json:"sender_avatar_url"`
Platform pgtype.Text `json:"platform"`
}
func (q *Queries) ListMessagesBeforeBySession(ctx context.Context, arg ListMessagesBeforeBySessionParams) ([]ListMessagesBeforeBySessionRow, error) {
rows, err := q.db.Query(ctx, listMessagesBeforeBySession, arg.SessionID, arg.CreatedAt, arg.MaxCount)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListMessagesBeforeBySessionRow
for rows.Next() {
var i ListMessagesBeforeBySessionRow
if err := rows.Scan(
&i.ID,
&i.BotID,
&i.SessionID,
&i.SenderChannelIdentityID,
&i.SenderUserID,
&i.ExternalMessageID,
&i.SourceReplyToMessageID,
&i.Role,
&i.Content,
&i.Metadata,
&i.Usage,
&i.CreatedAt,
&i.SenderDisplayName,
&i.SenderAvatarUrl,
&i.Platform,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listMessagesBySession = `-- 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 = $1
ORDER BY m.created_at ASC
LIMIT 10000
`
type ListMessagesBySessionRow struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
SessionID pgtype.UUID `json:"session_id"`
SenderChannelIdentityID pgtype.UUID `json:"sender_channel_identity_id"`
SenderUserID pgtype.UUID `json:"sender_user_id"`
ExternalMessageID pgtype.Text `json:"external_message_id"`
SourceReplyToMessageID pgtype.Text `json:"source_reply_to_message_id"`
Role string `json:"role"`
Content []byte `json:"content"`
Metadata []byte `json:"metadata"`
Usage []byte `json:"usage"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
SenderDisplayName pgtype.Text `json:"sender_display_name"`
SenderAvatarUrl pgtype.Text `json:"sender_avatar_url"`
Platform pgtype.Text `json:"platform"`
}
func (q *Queries) ListMessagesBySession(ctx context.Context, sessionID pgtype.UUID) ([]ListMessagesBySessionRow, error) {
rows, err := q.db.Query(ctx, listMessagesBySession, sessionID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListMessagesBySessionRow
for rows.Next() {
var i ListMessagesBySessionRow
if err := rows.Scan(
&i.ID,
&i.BotID,
&i.SessionID,
&i.SenderChannelIdentityID,
&i.SenderUserID,
&i.ExternalMessageID,
&i.SourceReplyToMessageID,
&i.Role,
&i.Content,
&i.Metadata,
&i.Usage,
&i.CreatedAt,
&i.SenderDisplayName,
&i.SenderAvatarUrl,
&i.Platform,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listMessagesLatest = `-- 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 = $1
ORDER BY m.created_at DESC
LIMIT $2
`
type ListMessagesLatestParams struct {
BotID pgtype.UUID `json:"bot_id"`
MaxCount int32 `json:"max_count"`
}
type ListMessagesLatestRow struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
SessionID pgtype.UUID `json:"session_id"`
SenderChannelIdentityID pgtype.UUID `json:"sender_channel_identity_id"`
SenderUserID pgtype.UUID `json:"sender_user_id"`
ExternalMessageID pgtype.Text `json:"external_message_id"`
SourceReplyToMessageID pgtype.Text `json:"source_reply_to_message_id"`
Role string `json:"role"`
Content []byte `json:"content"`
Metadata []byte `json:"metadata"`
Usage []byte `json:"usage"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
SenderDisplayName pgtype.Text `json:"sender_display_name"`
SenderAvatarUrl pgtype.Text `json:"sender_avatar_url"`
Platform pgtype.Text `json:"platform"`
}
func (q *Queries) ListMessagesLatest(ctx context.Context, arg ListMessagesLatestParams) ([]ListMessagesLatestRow, error) {
rows, err := q.db.Query(ctx, listMessagesLatest, arg.BotID, arg.MaxCount)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListMessagesLatestRow
for rows.Next() {
var i ListMessagesLatestRow
if err := rows.Scan(
&i.ID,
&i.BotID,
&i.SessionID,
&i.SenderChannelIdentityID,
&i.SenderUserID,
&i.ExternalMessageID,
&i.SourceReplyToMessageID,
&i.Role,
&i.Content,
&i.Metadata,
&i.Usage,
&i.CreatedAt,
&i.SenderDisplayName,
&i.SenderAvatarUrl,
&i.Platform,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listMessagesLatestBySession = `-- 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 = $1
ORDER BY m.created_at DESC
LIMIT $2
`
type ListMessagesLatestBySessionParams struct {
SessionID pgtype.UUID `json:"session_id"`
MaxCount int32 `json:"max_count"`
}
type ListMessagesLatestBySessionRow struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
SessionID pgtype.UUID `json:"session_id"`
SenderChannelIdentityID pgtype.UUID `json:"sender_channel_identity_id"`
SenderUserID pgtype.UUID `json:"sender_user_id"`
ExternalMessageID pgtype.Text `json:"external_message_id"`
SourceReplyToMessageID pgtype.Text `json:"source_reply_to_message_id"`
Role string `json:"role"`
Content []byte `json:"content"`
Metadata []byte `json:"metadata"`
Usage []byte `json:"usage"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
SenderDisplayName pgtype.Text `json:"sender_display_name"`
SenderAvatarUrl pgtype.Text `json:"sender_avatar_url"`
Platform pgtype.Text `json:"platform"`
}
func (q *Queries) ListMessagesLatestBySession(ctx context.Context, arg ListMessagesLatestBySessionParams) ([]ListMessagesLatestBySessionRow, error) {
rows, err := q.db.Query(ctx, listMessagesLatestBySession, arg.SessionID, arg.MaxCount)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListMessagesLatestBySessionRow
for rows.Next() {
var i ListMessagesLatestBySessionRow
if err := rows.Scan(
&i.ID,
&i.BotID,
&i.SessionID,
&i.SenderChannelIdentityID,
&i.SenderUserID,
&i.ExternalMessageID,
&i.SourceReplyToMessageID,
&i.Role,
&i.Content,
&i.Metadata,
&i.Usage,
&i.CreatedAt,
&i.SenderDisplayName,
&i.SenderAvatarUrl,
&i.Platform,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listMessagesSince = `-- 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 = $1
AND m.created_at >= $2
ORDER BY m.created_at ASC
`
type ListMessagesSinceParams struct {
BotID pgtype.UUID `json:"bot_id"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
type ListMessagesSinceRow struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
SessionID pgtype.UUID `json:"session_id"`
SenderChannelIdentityID pgtype.UUID `json:"sender_channel_identity_id"`
SenderUserID pgtype.UUID `json:"sender_user_id"`
ExternalMessageID pgtype.Text `json:"external_message_id"`
SourceReplyToMessageID pgtype.Text `json:"source_reply_to_message_id"`
Role string `json:"role"`
Content []byte `json:"content"`
Metadata []byte `json:"metadata"`
Usage []byte `json:"usage"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
SenderDisplayName pgtype.Text `json:"sender_display_name"`
SenderAvatarUrl pgtype.Text `json:"sender_avatar_url"`
Platform pgtype.Text `json:"platform"`
}
func (q *Queries) ListMessagesSince(ctx context.Context, arg ListMessagesSinceParams) ([]ListMessagesSinceRow, error) {
rows, err := q.db.Query(ctx, listMessagesSince, arg.BotID, arg.CreatedAt)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListMessagesSinceRow
for rows.Next() {
var i ListMessagesSinceRow
if err := rows.Scan(
&i.ID,
&i.BotID,
&i.SessionID,
&i.SenderChannelIdentityID,
&i.SenderUserID,
&i.ExternalMessageID,
&i.SourceReplyToMessageID,
&i.Role,
&i.Content,
&i.Metadata,
&i.Usage,
&i.CreatedAt,
&i.SenderDisplayName,
&i.SenderAvatarUrl,
&i.Platform,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listMessagesSinceBySession = `-- 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 = $1
AND m.created_at >= $2
ORDER BY m.created_at ASC
`
type ListMessagesSinceBySessionParams struct {
SessionID pgtype.UUID `json:"session_id"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
type ListMessagesSinceBySessionRow struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
SessionID pgtype.UUID `json:"session_id"`
SenderChannelIdentityID pgtype.UUID `json:"sender_channel_identity_id"`
SenderUserID pgtype.UUID `json:"sender_user_id"`
ExternalMessageID pgtype.Text `json:"external_message_id"`
SourceReplyToMessageID pgtype.Text `json:"source_reply_to_message_id"`
Role string `json:"role"`
Content []byte `json:"content"`
Metadata []byte `json:"metadata"`
Usage []byte `json:"usage"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
SenderDisplayName pgtype.Text `json:"sender_display_name"`
SenderAvatarUrl pgtype.Text `json:"sender_avatar_url"`
Platform pgtype.Text `json:"platform"`
}
func (q *Queries) ListMessagesSinceBySession(ctx context.Context, arg ListMessagesSinceBySessionParams) ([]ListMessagesSinceBySessionRow, error) {
rows, err := q.db.Query(ctx, listMessagesSinceBySession, arg.SessionID, arg.CreatedAt)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListMessagesSinceBySessionRow
for rows.Next() {
var i ListMessagesSinceBySessionRow
if err := rows.Scan(
&i.ID,
&i.BotID,
&i.SessionID,
&i.SenderChannelIdentityID,
&i.SenderUserID,
&i.ExternalMessageID,
&i.SourceReplyToMessageID,
&i.Role,
&i.Content,
&i.Metadata,
&i.Usage,
&i.CreatedAt,
&i.SenderDisplayName,
&i.SenderAvatarUrl,
&i.Platform,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listObservedConversationsByChannelIdentity = `-- 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 = $1
AND m.sender_channel_identity_id = $2::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'
ELSE 'group'
END AS conversation_type,
r.external_conversation_id AS conversation_id,
COALESCE(r.external_thread_id, '') AS thread_id,
COALESCE(r.metadata->>'conversation_name', '')::text AS conversation_name,
rr.last_observed_at
FROM observed_routes rr
JOIN bot_channel_routes r ON r.id = rr.route_id
WHERE LOWER(COALESCE(r.conversation_type, '')) NOT IN ('', 'p2p', 'private', 'direct', 'dm')
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
`
type ListObservedConversationsByChannelIdentityParams struct {
BotID pgtype.UUID `json:"bot_id"`
ChannelIdentityID pgtype.UUID `json:"channel_identity_id"`
}
type ListObservedConversationsByChannelIdentityRow struct {
RouteID pgtype.UUID `json:"route_id"`
Channel string `json:"channel"`
ConversationType string `json:"conversation_type"`
ConversationID string `json:"conversation_id"`
ThreadID string `json:"thread_id"`
ConversationName string `json:"conversation_name"`
LastObservedAt pgtype.Timestamptz `json:"last_observed_at"`
}
func (q *Queries) ListObservedConversationsByChannelIdentity(ctx context.Context, arg ListObservedConversationsByChannelIdentityParams) ([]ListObservedConversationsByChannelIdentityRow, error) {
rows, err := q.db.Query(ctx, listObservedConversationsByChannelIdentity, arg.BotID, arg.ChannelIdentityID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListObservedConversationsByChannelIdentityRow
for rows.Next() {
var i ListObservedConversationsByChannelIdentityRow
if err := rows.Scan(
&i.RouteID,
&i.Channel,
&i.ConversationType,
&i.ConversationID,
&i.ThreadID,
&i.ConversationName,
&i.LastObservedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listUncompactedMessagesBySession = `-- 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
`
type ListUncompactedMessagesBySessionRow struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
SessionID pgtype.UUID `json:"session_id"`
Role string `json:"role"`
Content []byte `json:"content"`
Usage []byte `json:"usage"`
SenderChannelIdentityID pgtype.UUID `json:"sender_channel_identity_id"`
CompactID pgtype.UUID `json:"compact_id"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
}
func (q *Queries) ListUncompactedMessagesBySession(ctx context.Context, sessionID pgtype.UUID) ([]ListUncompactedMessagesBySessionRow, error) {
rows, err := q.db.Query(ctx, listUncompactedMessagesBySession, sessionID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListUncompactedMessagesBySessionRow
for rows.Next() {
var i ListUncompactedMessagesBySessionRow
if err := rows.Scan(
&i.ID,
&i.BotID,
&i.SessionID,
&i.Role,
&i.Content,
&i.Usage,
&i.SenderChannelIdentityID,
&i.CompactID,
&i.CreatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const markMessagesCompacted = `-- name: MarkMessagesCompacted :exec
UPDATE bot_history_messages
SET compact_id = $1
WHERE id = ANY($2::uuid[])
`
type MarkMessagesCompactedParams struct {
CompactID pgtype.UUID `json:"compact_id"`
Column2 []pgtype.UUID `json:"column_2"`
}
func (q *Queries) MarkMessagesCompacted(ctx context.Context, arg MarkMessagesCompactedParams) error {
_, err := q.db.Exec(ctx, markMessagesCompacted, arg.CompactID, arg.Column2)
return err
}
const searchMessages = `-- 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 = $1
AND ($2::uuid IS NULL OR m.session_id = $2::uuid)
AND ($3::uuid IS NULL OR m.sender_channel_identity_id = $3::uuid)
AND ($4::timestamptz IS NULL OR m.created_at >= $4::timestamptz)
AND ($5::timestamptz IS NULL OR m.created_at <= $5::timestamptz)
AND ($6::text IS NULL OR m.role = $6::text)
AND ($7::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 '%' || $7::text || '%')
ORDER BY m.created_at DESC
LIMIT $8
`
type SearchMessagesParams struct {
BotID pgtype.UUID `json:"bot_id"`
SessionID pgtype.UUID `json:"session_id"`
ContactID pgtype.UUID `json:"contact_id"`
StartTime pgtype.Timestamptz `json:"start_time"`
EndTime pgtype.Timestamptz `json:"end_time"`
Role pgtype.Text `json:"role"`
Keyword pgtype.Text `json:"keyword"`
MaxCount int32 `json:"max_count"`
}
type SearchMessagesRow struct {
ID pgtype.UUID `json:"id"`
BotID pgtype.UUID `json:"bot_id"`
SessionID pgtype.UUID `json:"session_id"`
SenderChannelIdentityID pgtype.UUID `json:"sender_channel_identity_id"`
Role string `json:"role"`
Content []byte `json:"content"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
SenderDisplayName pgtype.Text `json:"sender_display_name"`
Platform pgtype.Text `json:"platform"`
}
func (q *Queries) SearchMessages(ctx context.Context, arg SearchMessagesParams) ([]SearchMessagesRow, error) {
rows, err := q.db.Query(ctx, searchMessages,
arg.BotID,
arg.SessionID,
arg.ContactID,
arg.StartTime,
arg.EndTime,
arg.Role,
arg.Keyword,
arg.MaxCount,
)
if err != nil {
return nil, err
}
defer rows.Close()
var items []SearchMessagesRow
for rows.Next() {
var i SearchMessagesRow
if err := rows.Scan(
&i.ID,
&i.BotID,
&i.SessionID,
&i.SenderChannelIdentityID,
&i.Role,
&i.Content,
&i.CreatedAt,
&i.SenderDisplayName,
&i.Platform,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}