mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-27 07:16:19 +09:00
6aebbe9279
Major changes: 1. Core Architecture: Decoupled Bots from Users. Bots now have independent lifecycles, member management (bot_members), and dedicated configurations. 2. Channel Gateway: - Implemented a unified Channel Manager supporting Feishu, Telegram, and Local (Web/CLI) adapters. - Added message processing pipeline to normalize interactions across different platforms. - Introduced a Contact system for identity binding and guest access policies. 3. Database & Tooling: - Consolidated all migrations into 0001_init with updated schema for bots, channels, and contacts. - Optimized sqlc.yaml to automatically track the migrations directory. 4. Agent Enhancements: - Introduced ToolContext to provide Agents with platform-aware execution capabilities (e.g., messaging, contact lookups). - Added tool logging and fallback mechanisms for toolChoice execution. 5. UI & Docs: Updated frontend stores, UI components, and Swagger documentation to align with the new Bot-centric model.
473 lines
11 KiB
Go
473 lines
11 KiB
Go
// Code generated by sqlc. DO NOT EDIT.
|
|
// versions:
|
|
// sqlc v1.30.0
|
|
// source: contacts.sql
|
|
|
|
package sqlc
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
)
|
|
|
|
const createContact = `-- name: CreateContact :one
|
|
INSERT INTO contacts (bot_id, user_id, display_name, alias, tags, status, metadata)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
RETURNING id, bot_id, user_id, display_name, alias, tags, status, metadata, created_at, updated_at
|
|
`
|
|
|
|
type CreateContactParams struct {
|
|
BotID pgtype.UUID `json:"bot_id"`
|
|
UserID pgtype.UUID `json:"user_id"`
|
|
DisplayName pgtype.Text `json:"display_name"`
|
|
Alias pgtype.Text `json:"alias"`
|
|
Tags []string `json:"tags"`
|
|
Status string `json:"status"`
|
|
Metadata []byte `json:"metadata"`
|
|
}
|
|
|
|
func (q *Queries) CreateContact(ctx context.Context, arg CreateContactParams) (Contact, error) {
|
|
row := q.db.QueryRow(ctx, createContact,
|
|
arg.BotID,
|
|
arg.UserID,
|
|
arg.DisplayName,
|
|
arg.Alias,
|
|
arg.Tags,
|
|
arg.Status,
|
|
arg.Metadata,
|
|
)
|
|
var i Contact
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.BotID,
|
|
&i.UserID,
|
|
&i.DisplayName,
|
|
&i.Alias,
|
|
&i.Tags,
|
|
&i.Status,
|
|
&i.Metadata,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const createContactBindToken = `-- name: CreateContactBindToken :one
|
|
INSERT INTO contact_bind_tokens (bot_id, contact_id, token, target_platform, target_external_id, issued_by_user_id, expires_at)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
RETURNING id, bot_id, contact_id, token, target_platform, target_external_id, issued_by_user_id, expires_at, used_at, created_at
|
|
`
|
|
|
|
type CreateContactBindTokenParams struct {
|
|
BotID pgtype.UUID `json:"bot_id"`
|
|
ContactID pgtype.UUID `json:"contact_id"`
|
|
Token string `json:"token"`
|
|
TargetPlatform pgtype.Text `json:"target_platform"`
|
|
TargetExternalID pgtype.Text `json:"target_external_id"`
|
|
IssuedByUserID pgtype.UUID `json:"issued_by_user_id"`
|
|
ExpiresAt pgtype.Timestamptz `json:"expires_at"`
|
|
}
|
|
|
|
func (q *Queries) CreateContactBindToken(ctx context.Context, arg CreateContactBindTokenParams) (ContactBindToken, error) {
|
|
row := q.db.QueryRow(ctx, createContactBindToken,
|
|
arg.BotID,
|
|
arg.ContactID,
|
|
arg.Token,
|
|
arg.TargetPlatform,
|
|
arg.TargetExternalID,
|
|
arg.IssuedByUserID,
|
|
arg.ExpiresAt,
|
|
)
|
|
var i ContactBindToken
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.BotID,
|
|
&i.ContactID,
|
|
&i.Token,
|
|
&i.TargetPlatform,
|
|
&i.TargetExternalID,
|
|
&i.IssuedByUserID,
|
|
&i.ExpiresAt,
|
|
&i.UsedAt,
|
|
&i.CreatedAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getContactBindToken = `-- name: GetContactBindToken :one
|
|
SELECT id, bot_id, contact_id, token, target_platform, target_external_id, issued_by_user_id, expires_at, used_at, created_at
|
|
FROM contact_bind_tokens
|
|
WHERE token = $1
|
|
LIMIT 1
|
|
`
|
|
|
|
func (q *Queries) GetContactBindToken(ctx context.Context, token string) (ContactBindToken, error) {
|
|
row := q.db.QueryRow(ctx, getContactBindToken, token)
|
|
var i ContactBindToken
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.BotID,
|
|
&i.ContactID,
|
|
&i.Token,
|
|
&i.TargetPlatform,
|
|
&i.TargetExternalID,
|
|
&i.IssuedByUserID,
|
|
&i.ExpiresAt,
|
|
&i.UsedAt,
|
|
&i.CreatedAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getContactByID = `-- name: GetContactByID :one
|
|
SELECT id, bot_id, user_id, display_name, alias, tags, status, metadata, created_at, updated_at
|
|
FROM contacts
|
|
WHERE id = $1
|
|
LIMIT 1
|
|
`
|
|
|
|
func (q *Queries) GetContactByID(ctx context.Context, id pgtype.UUID) (Contact, error) {
|
|
row := q.db.QueryRow(ctx, getContactByID, id)
|
|
var i Contact
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.BotID,
|
|
&i.UserID,
|
|
&i.DisplayName,
|
|
&i.Alias,
|
|
&i.Tags,
|
|
&i.Status,
|
|
&i.Metadata,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getContactByUserID = `-- name: GetContactByUserID :one
|
|
SELECT id, bot_id, user_id, display_name, alias, tags, status, metadata, created_at, updated_at
|
|
FROM contacts
|
|
WHERE bot_id = $1 AND user_id = $2
|
|
LIMIT 1
|
|
`
|
|
|
|
type GetContactByUserIDParams struct {
|
|
BotID pgtype.UUID `json:"bot_id"`
|
|
UserID pgtype.UUID `json:"user_id"`
|
|
}
|
|
|
|
func (q *Queries) GetContactByUserID(ctx context.Context, arg GetContactByUserIDParams) (Contact, error) {
|
|
row := q.db.QueryRow(ctx, getContactByUserID, arg.BotID, arg.UserID)
|
|
var i Contact
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.BotID,
|
|
&i.UserID,
|
|
&i.DisplayName,
|
|
&i.Alias,
|
|
&i.Tags,
|
|
&i.Status,
|
|
&i.Metadata,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const getContactChannelByIdentity = `-- name: GetContactChannelByIdentity :one
|
|
SELECT id, bot_id, contact_id, platform, external_id, metadata, created_at, updated_at
|
|
FROM contact_channels
|
|
WHERE bot_id = $1 AND platform = $2 AND external_id = $3
|
|
LIMIT 1
|
|
`
|
|
|
|
type GetContactChannelByIdentityParams struct {
|
|
BotID pgtype.UUID `json:"bot_id"`
|
|
Platform string `json:"platform"`
|
|
ExternalID string `json:"external_id"`
|
|
}
|
|
|
|
func (q *Queries) GetContactChannelByIdentity(ctx context.Context, arg GetContactChannelByIdentityParams) (ContactChannel, error) {
|
|
row := q.db.QueryRow(ctx, getContactChannelByIdentity, arg.BotID, arg.Platform, arg.ExternalID)
|
|
var i ContactChannel
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.BotID,
|
|
&i.ContactID,
|
|
&i.Platform,
|
|
&i.ExternalID,
|
|
&i.Metadata,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const listContactChannelsByContact = `-- name: ListContactChannelsByContact :many
|
|
SELECT id, bot_id, contact_id, platform, external_id, metadata, created_at, updated_at
|
|
FROM contact_channels
|
|
WHERE contact_id = $1
|
|
ORDER BY created_at DESC
|
|
`
|
|
|
|
func (q *Queries) ListContactChannelsByContact(ctx context.Context, contactID pgtype.UUID) ([]ContactChannel, error) {
|
|
rows, err := q.db.Query(ctx, listContactChannelsByContact, contactID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []ContactChannel
|
|
for rows.Next() {
|
|
var i ContactChannel
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.BotID,
|
|
&i.ContactID,
|
|
&i.Platform,
|
|
&i.ExternalID,
|
|
&i.Metadata,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listContactsByBot = `-- name: ListContactsByBot :many
|
|
SELECT id, bot_id, user_id, display_name, alias, tags, status, metadata, created_at, updated_at
|
|
FROM contacts
|
|
WHERE bot_id = $1
|
|
ORDER BY created_at DESC
|
|
`
|
|
|
|
func (q *Queries) ListContactsByBot(ctx context.Context, botID pgtype.UUID) ([]Contact, error) {
|
|
rows, err := q.db.Query(ctx, listContactsByBot, botID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []Contact
|
|
for rows.Next() {
|
|
var i Contact
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.BotID,
|
|
&i.UserID,
|
|
&i.DisplayName,
|
|
&i.Alias,
|
|
&i.Tags,
|
|
&i.Status,
|
|
&i.Metadata,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const markContactBindTokenUsed = `-- name: MarkContactBindTokenUsed :one
|
|
UPDATE contact_bind_tokens
|
|
SET used_at = now()
|
|
WHERE id = $1
|
|
RETURNING id, bot_id, contact_id, token, target_platform, target_external_id, issued_by_user_id, expires_at, used_at, created_at
|
|
`
|
|
|
|
func (q *Queries) MarkContactBindTokenUsed(ctx context.Context, id pgtype.UUID) (ContactBindToken, error) {
|
|
row := q.db.QueryRow(ctx, markContactBindTokenUsed, id)
|
|
var i ContactBindToken
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.BotID,
|
|
&i.ContactID,
|
|
&i.Token,
|
|
&i.TargetPlatform,
|
|
&i.TargetExternalID,
|
|
&i.IssuedByUserID,
|
|
&i.ExpiresAt,
|
|
&i.UsedAt,
|
|
&i.CreatedAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const searchContacts = `-- name: SearchContacts :many
|
|
SELECT id, bot_id, user_id, display_name, alias, tags, status, metadata, created_at, updated_at
|
|
FROM contacts
|
|
WHERE bot_id = $1
|
|
AND (
|
|
display_name ILIKE $2
|
|
OR alias ILIKE $2
|
|
OR EXISTS (
|
|
SELECT 1 FROM unnest(tags) AS tag WHERE tag ILIKE $2
|
|
)
|
|
)
|
|
ORDER BY created_at DESC
|
|
`
|
|
|
|
type SearchContactsParams struct {
|
|
BotID pgtype.UUID `json:"bot_id"`
|
|
Query pgtype.Text `json:"query"`
|
|
}
|
|
|
|
func (q *Queries) SearchContacts(ctx context.Context, arg SearchContactsParams) ([]Contact, error) {
|
|
rows, err := q.db.Query(ctx, searchContacts, arg.BotID, arg.Query)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []Contact
|
|
for rows.Next() {
|
|
var i Contact
|
|
if err := rows.Scan(
|
|
&i.ID,
|
|
&i.BotID,
|
|
&i.UserID,
|
|
&i.DisplayName,
|
|
&i.Alias,
|
|
&i.Tags,
|
|
&i.Status,
|
|
&i.Metadata,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const updateContact = `-- name: UpdateContact :one
|
|
UPDATE contacts
|
|
SET display_name = COALESCE($1, display_name),
|
|
alias = COALESCE($2, alias),
|
|
tags = COALESCE($3, tags),
|
|
status = COALESCE(NULLIF($4::text, ''), status),
|
|
metadata = COALESCE($5, metadata),
|
|
updated_at = now()
|
|
WHERE id = $6
|
|
RETURNING id, bot_id, user_id, display_name, alias, tags, status, metadata, created_at, updated_at
|
|
`
|
|
|
|
type UpdateContactParams struct {
|
|
DisplayName pgtype.Text `json:"display_name"`
|
|
Alias pgtype.Text `json:"alias"`
|
|
Tags []string `json:"tags"`
|
|
Status string `json:"status"`
|
|
Metadata []byte `json:"metadata"`
|
|
ID pgtype.UUID `json:"id"`
|
|
}
|
|
|
|
func (q *Queries) UpdateContact(ctx context.Context, arg UpdateContactParams) (Contact, error) {
|
|
row := q.db.QueryRow(ctx, updateContact,
|
|
arg.DisplayName,
|
|
arg.Alias,
|
|
arg.Tags,
|
|
arg.Status,
|
|
arg.Metadata,
|
|
arg.ID,
|
|
)
|
|
var i Contact
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.BotID,
|
|
&i.UserID,
|
|
&i.DisplayName,
|
|
&i.Alias,
|
|
&i.Tags,
|
|
&i.Status,
|
|
&i.Metadata,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const updateContactUser = `-- name: UpdateContactUser :one
|
|
UPDATE contacts
|
|
SET user_id = $2,
|
|
updated_at = now()
|
|
WHERE id = $1
|
|
RETURNING id, bot_id, user_id, display_name, alias, tags, status, metadata, created_at, updated_at
|
|
`
|
|
|
|
type UpdateContactUserParams struct {
|
|
ID pgtype.UUID `json:"id"`
|
|
UserID pgtype.UUID `json:"user_id"`
|
|
}
|
|
|
|
func (q *Queries) UpdateContactUser(ctx context.Context, arg UpdateContactUserParams) (Contact, error) {
|
|
row := q.db.QueryRow(ctx, updateContactUser, arg.ID, arg.UserID)
|
|
var i Contact
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.BotID,
|
|
&i.UserID,
|
|
&i.DisplayName,
|
|
&i.Alias,
|
|
&i.Tags,
|
|
&i.Status,
|
|
&i.Metadata,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const upsertContactChannel = `-- name: UpsertContactChannel :one
|
|
INSERT INTO contact_channels (bot_id, contact_id, platform, external_id, metadata)
|
|
VALUES ($1, $2, $3, $4, $5)
|
|
ON CONFLICT (bot_id, platform, external_id)
|
|
DO UPDATE SET
|
|
contact_id = EXCLUDED.contact_id,
|
|
metadata = EXCLUDED.metadata,
|
|
updated_at = now()
|
|
RETURNING id, bot_id, contact_id, platform, external_id, metadata, created_at, updated_at
|
|
`
|
|
|
|
type UpsertContactChannelParams struct {
|
|
BotID pgtype.UUID `json:"bot_id"`
|
|
ContactID pgtype.UUID `json:"contact_id"`
|
|
Platform string `json:"platform"`
|
|
ExternalID string `json:"external_id"`
|
|
Metadata []byte `json:"metadata"`
|
|
}
|
|
|
|
func (q *Queries) UpsertContactChannel(ctx context.Context, arg UpsertContactChannelParams) (ContactChannel, error) {
|
|
row := q.db.QueryRow(ctx, upsertContactChannel,
|
|
arg.BotID,
|
|
arg.ContactID,
|
|
arg.Platform,
|
|
arg.ExternalID,
|
|
arg.Metadata,
|
|
)
|
|
var i ContactChannel
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.BotID,
|
|
&i.ContactID,
|
|
&i.Platform,
|
|
&i.ExternalID,
|
|
&i.Metadata,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
)
|
|
return i, err
|
|
}
|