Changeset 0.23.0 (#153)
This commit is contained in:
@@ -3,6 +3,7 @@ package models
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -128,6 +129,8 @@ type ProviderConfig struct {
|
||||
Settings JSONMap `json:"settings,omitempty" db:"settings"`
|
||||
IsActive bool `json:"is_active" db:"is_active"`
|
||||
IsPrivate bool `json:"is_private" db:"is_private"`
|
||||
ProxyMode string `json:"proxy_mode" db:"proxy_mode"`
|
||||
ProxyURL *string `json:"proxy_url,omitempty" db:"proxy_url"`
|
||||
}
|
||||
|
||||
// HasKey returns true if an encrypted API key is stored.
|
||||
@@ -146,6 +149,8 @@ type ProviderConfigPatch struct {
|
||||
Settings JSONMap `json:"settings,omitempty"`
|
||||
IsActive *bool `json:"is_active,omitempty"`
|
||||
IsPrivate *bool `json:"is_private,omitempty"`
|
||||
ProxyMode *string `json:"proxy_mode,omitempty"`
|
||||
ProxyURL *string `json:"proxy_url,omitempty"`
|
||||
}
|
||||
|
||||
// =========================================
|
||||
@@ -194,6 +199,7 @@ type ModelPricing struct {
|
||||
type Persona struct {
|
||||
BaseModel
|
||||
Name string `json:"name" db:"name"`
|
||||
Handle string `json:"handle,omitempty" db:"handle"`
|
||||
Description string `json:"description,omitempty" db:"description"`
|
||||
Icon string `json:"icon,omitempty" db:"icon"`
|
||||
Avatar string `json:"avatar,omitempty" db:"avatar"`
|
||||
@@ -227,6 +233,7 @@ type Persona struct {
|
||||
|
||||
type PersonaPatch struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
Handle *string `json:"handle,omitempty"`
|
||||
Description *string `json:"description,omitempty"`
|
||||
Icon *string `json:"icon,omitempty"`
|
||||
Avatar *string `json:"avatar,omitempty"`
|
||||
@@ -278,6 +285,7 @@ type UserModelSetting struct {
|
||||
BaseModel
|
||||
UserID string `json:"user_id" db:"user_id"`
|
||||
ModelID string `json:"model_id" db:"model_id"`
|
||||
ProviderConfigID *string `json:"provider_config_id,omitempty" db:"provider_config_id"`
|
||||
Hidden bool `json:"hidden" db:"hidden"`
|
||||
PreferredTemperature *float64 `json:"preferred_temperature,omitempty" db:"preferred_temperature"`
|
||||
PreferredMaxTokens *int `json:"preferred_max_tokens,omitempty" db:"preferred_max_tokens"`
|
||||
@@ -285,12 +293,24 @@ type UserModelSetting struct {
|
||||
}
|
||||
|
||||
type UserModelSettingPatch struct {
|
||||
ProviderConfigID *string `json:"provider_config_id,omitempty"`
|
||||
Hidden *bool `json:"hidden,omitempty"`
|
||||
PreferredTemperature *float64 `json:"preferred_temperature,omitempty"`
|
||||
PreferredMaxTokens *int `json:"preferred_max_tokens,omitempty"`
|
||||
SortOrder *int `json:"sort_order,omitempty"`
|
||||
}
|
||||
|
||||
// HiddenEntry identifies a model+provider pair for bulk visibility operations.
|
||||
type HiddenEntry struct {
|
||||
ModelID string `json:"model_id"`
|
||||
ProviderConfigID string `json:"provider_config_id"`
|
||||
}
|
||||
|
||||
// CompositeModelKey builds the composite key used for per-provider model preferences.
|
||||
func CompositeModelKey(providerConfigID, modelID string) string {
|
||||
return providerConfigID + ":" + modelID
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// CHANNELS
|
||||
// =========================================
|
||||
@@ -319,41 +339,47 @@ type Channel struct {
|
||||
|
||||
type Message struct {
|
||||
BaseModel
|
||||
ChannelID string `json:"channel_id" db:"channel_id"`
|
||||
Role string `json:"role" db:"role"`
|
||||
Content string `json:"content" db:"content"`
|
||||
Model string `json:"model,omitempty" db:"model"`
|
||||
TokensUsed int `json:"tokens_used,omitempty" db:"tokens_used"`
|
||||
ToolCalls JSONMap `json:"tool_calls,omitempty" db:"tool_calls"`
|
||||
Metadata JSONMap `json:"metadata,omitempty" db:"metadata"`
|
||||
ParentID *string `json:"parent_id,omitempty" db:"parent_id"`
|
||||
SiblingIndex int `json:"sibling_index" db:"sibling_index"`
|
||||
ParticipantType string `json:"participant_type,omitempty" db:"participant_type"`
|
||||
ParticipantID string `json:"participant_id,omitempty" db:"participant_id"`
|
||||
DeletedAt *time.Time `json:"deleted_at,omitempty" db:"deleted_at"`
|
||||
ChannelID string `json:"channel_id" db:"channel_id"`
|
||||
Role string `json:"role" db:"role"`
|
||||
Content string `json:"content" db:"content"`
|
||||
Model string `json:"model,omitempty" db:"model"`
|
||||
TokensUsed int `json:"tokens_used,omitempty" db:"tokens_used"`
|
||||
ToolCalls JSONMap `json:"tool_calls,omitempty" db:"tool_calls"`
|
||||
Metadata JSONMap `json:"metadata,omitempty" db:"metadata"`
|
||||
ParentID *string `json:"parent_id,omitempty" db:"parent_id"`
|
||||
SiblingIndex int `json:"sibling_index" db:"sibling_index"`
|
||||
ParticipantType string `json:"participant_type,omitempty" db:"participant_type"`
|
||||
ParticipantID string `json:"participant_id,omitempty" db:"participant_id"`
|
||||
ProviderConfigID *string `json:"provider_config_id,omitempty" db:"provider_config_id"`
|
||||
DeletedAt *time.Time `json:"deleted_at,omitempty" db:"deleted_at"`
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// CHANNEL MEMBERS, MODELS, CURSORS
|
||||
// CHANNEL PARTICIPANTS, MODELS, CURSORS
|
||||
// =========================================
|
||||
|
||||
type ChannelMember struct {
|
||||
ID string `json:"id" db:"id"`
|
||||
ChannelID string `json:"channel_id" db:"channel_id"`
|
||||
UserID string `json:"user_id" db:"user_id"`
|
||||
Role string `json:"role" db:"role"`
|
||||
JoinedAt time.Time `json:"joined_at" db:"joined_at"`
|
||||
LastReadAt time.Time `json:"last_read_at" db:"last_read_at"`
|
||||
type ChannelParticipant struct {
|
||||
ID string `json:"id" db:"id"`
|
||||
ChannelID string `json:"channel_id" db:"channel_id"`
|
||||
ParticipantType string `json:"participant_type" db:"participant_type"`
|
||||
ParticipantID string `json:"participant_id" db:"participant_id"`
|
||||
Role string `json:"role" db:"role"`
|
||||
DisplayName *string `json:"display_name,omitempty" db:"display_name"`
|
||||
AvatarURL *string `json:"avatar_url,omitempty" db:"avatar_url"`
|
||||
JoinedAt time.Time `json:"joined_at" db:"joined_at"`
|
||||
LastReadAt time.Time `json:"last_read_at" db:"last_read_at"`
|
||||
}
|
||||
|
||||
type ChannelModel struct {
|
||||
ID string `json:"id" db:"id"`
|
||||
ChannelID string `json:"channel_id" db:"channel_id"`
|
||||
ModelID string `json:"model_id" db:"model_id"`
|
||||
ProviderConfigID string `json:"provider_config_id,omitempty" db:"provider_config_id"`
|
||||
DisplayName string `json:"display_name,omitempty" db:"display_name"`
|
||||
SystemPrompt string `json:"system_prompt,omitempty" db:"system_prompt"`
|
||||
IsDefault bool `json:"is_default" db:"is_default"`
|
||||
ID string `json:"id" db:"id"`
|
||||
ChannelID string `json:"channel_id" db:"channel_id"`
|
||||
ModelID string `json:"model_id" db:"model_id"`
|
||||
ProviderConfigID string `json:"provider_config_id,omitempty" db:"provider_config_id"`
|
||||
PersonaID *string `json:"persona_id,omitempty" db:"persona_id"`
|
||||
Handle string `json:"handle,omitempty" db:"handle"`
|
||||
DisplayName string `json:"display_name,omitempty" db:"display_name"`
|
||||
SystemPrompt string `json:"system_prompt,omitempty" db:"system_prompt"`
|
||||
IsDefault bool `json:"is_default" db:"is_default"`
|
||||
}
|
||||
|
||||
type ChannelCursor struct {
|
||||
@@ -364,6 +390,56 @@ type ChannelCursor struct {
|
||||
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// PERSONA GROUPS (v0.23.0)
|
||||
// =========================================
|
||||
|
||||
type PersonaGroup struct {
|
||||
BaseModel
|
||||
Name string `json:"name" db:"name"`
|
||||
Description string `json:"description,omitempty" db:"description"`
|
||||
OwnerID string `json:"owner_id" db:"owner_id"`
|
||||
Scope string `json:"scope" db:"scope"`
|
||||
TeamID *string `json:"team_id,omitempty" db:"team_id"`
|
||||
Members []PersonaGroupMember `json:"members,omitempty" db:"-"`
|
||||
}
|
||||
|
||||
type PersonaGroupMember struct {
|
||||
ID string `json:"id" db:"id"`
|
||||
GroupID string `json:"group_id" db:"group_id"`
|
||||
PersonaID string `json:"persona_id" db:"persona_id"`
|
||||
IsLeader bool `json:"is_leader" db:"is_leader"`
|
||||
SortOrder int `json:"sort_order" db:"sort_order"`
|
||||
// Joined from personas table for API responses
|
||||
PersonaName string `json:"persona_name,omitempty" db:"-"`
|
||||
PersonaHandle string `json:"persona_handle,omitempty" db:"-"`
|
||||
PersonaAvatar string `json:"persona_avatar,omitempty" db:"-"`
|
||||
}
|
||||
|
||||
// HandleFromName generates a URL-safe @mention handle from a display name.
|
||||
// "Veronica Sharpe" → "veronica-sharpe"
|
||||
func HandleFromName(name string) string {
|
||||
h := strings.ToLower(strings.TrimSpace(name))
|
||||
h = strings.Map(func(r rune) rune {
|
||||
if (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || r == '-' {
|
||||
return r
|
||||
}
|
||||
if r == ' ' || r == '_' {
|
||||
return '-'
|
||||
}
|
||||
return -1
|
||||
}, h)
|
||||
// Collapse multiple hyphens
|
||||
for strings.Contains(h, "--") {
|
||||
h = strings.ReplaceAll(h, "--", "-")
|
||||
}
|
||||
h = strings.Trim(h, "-")
|
||||
if len(h) > 50 {
|
||||
h = h[:50]
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// ORGANIZATION
|
||||
// =========================================
|
||||
@@ -635,6 +711,7 @@ type UserModel struct {
|
||||
// Persona fields — always emitted so frontend can branch on is_persona.
|
||||
IsPersona bool `json:"is_persona"`
|
||||
PersonaID string `json:"persona_id,omitempty"`
|
||||
PersonaHandle string `json:"persona_handle,omitempty"`
|
||||
PersonaScope string `json:"persona_scope,omitempty"`
|
||||
PersonaAvatar string `json:"persona_avatar,omitempty"`
|
||||
PersonaTeamName string `json:"persona_team_name,omitempty"`
|
||||
|
||||
Reference in New Issue
Block a user