Initial commit: CarrotAssistant backend (Go + Gin + SQLite, OpenAI-compatible agent runtime)
This commit is contained in:
110
internal/store/models.go
Normal file
110
internal/store/models.go
Normal file
@@ -0,0 +1,110 @@
|
||||
// Package store defines the persistence layer for CarrotAssistant.
|
||||
//
|
||||
// All persistent structured state lives here: admin accounts, applications,
|
||||
// model configurations, skill metadata, chat sessions and messages, and
|
||||
// audit logs. Skill *content* itself (the markdown file) lives on disk and
|
||||
// is managed by the skill package; this package only stores the metadata
|
||||
// needed to locate and govern that file (status, version, ownership).
|
||||
package store
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/datatypes"
|
||||
)
|
||||
|
||||
// AdminUser is an operator who can log in to the admin console.
|
||||
type AdminUser struct {
|
||||
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
Username string `gorm:"uniqueIndex;size:64;not null" json:"username"`
|
||||
PasswordHash string `gorm:"size:255;not null" json:"-"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// App is a target application (a forum, a resource site, ...). Each App owns
|
||||
// a set of Skills and exposes a Chat API guarded by its access token.
|
||||
type App struct {
|
||||
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
Slug string `gorm:"uniqueIndex;size:64;not null" json:"slug"`
|
||||
Name string `gorm:"size:128;not null" json:"name"`
|
||||
Description string `gorm:"size:512" json:"description"`
|
||||
TokenHash string `gorm:"size:255;not null" json:"-"` // SHA-256 hash of the access token; never store plaintext
|
||||
ModelConfigID *int64 `gorm:"index" json:"model_config_id,omitempty"`
|
||||
Status string `gorm:"size:32;not null;default:'active'" json:"status"` // active | disabled
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// ModelConfig describes an OpenAI-compatible LLM endpoint. Any provider
|
||||
// speaking the OpenAI Chat Completions + tool-calling protocol (OpenAI,
|
||||
// DeepSeek, Moonshot, vLLM, Ollama, ...) can be wired in here.
|
||||
type ModelConfig struct {
|
||||
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
Name string `gorm:"uniqueIndex;size:64;not null" json:"name"`
|
||||
BaseURL string `gorm:"size:255;not null" json:"base_url"`
|
||||
APIKeyEncrypted string `gorm:"size:512;not null" json:"-"` // AES-GCM ciphertext, base64
|
||||
APIKeyPreview string `gorm:"size:16" json:"api_key_preview"` // last 4 chars, display only
|
||||
DefaultModel string `gorm:"size:64;not null" json:"default_model"`
|
||||
SupportsTools bool `gorm:"not null;default:true" json:"supports_tools"`
|
||||
MaxTokens int `gorm:"default:0" json:"max_tokens"` // 0 = leave unset
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// Skill is the metadata row for a skill markdown file. The markdown content
|
||||
// (system prompt + tool definitions) lives at FilePath; this row only governs
|
||||
// lifecycle (draft/published/archived), versioning, and ownership.
|
||||
type Skill struct {
|
||||
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
AppID int64 `gorm:"index;not null" json:"app_id"`
|
||||
Slug string `gorm:"size:64;not null" json:"slug"` // unique within app
|
||||
Name string `gorm:"size:128;not null" json:"name"`
|
||||
Description string `gorm:"size:512" json:"description"`
|
||||
FilePath string `gorm:"size:512;not null" json:"file_path"` // path under SkillsDir
|
||||
Version int `gorm:"not null;default:1" json:"version"`
|
||||
Status string `gorm:"size:32;not null;default:'draft'" json:"status"` // draft | published | archived
|
||||
Source string `gorm:"size:32" json:"source"` // openapi | markdown | source | manual
|
||||
PublishedAt *time.Time `json:"published_at,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// Session is a chat conversation between an end-user and an App's assistant.
|
||||
type Session struct {
|
||||
ID string `gorm:"primaryKey;type:text" json:"id"` // UUID
|
||||
AppID int64 `gorm:"index;not null" json:"app_id"`
|
||||
Title string `gorm:"size:255" json:"title"`
|
||||
MessageCount int `gorm:"not null;default:0" json:"message_count"`
|
||||
// PendingConfirmation, when non-empty, holds a JSON blob describing a
|
||||
// mutating tool call awaiting the user's approval. The chat stream pauses
|
||||
// until POST /chat/confirm resolves it. Empty = no pending call.
|
||||
PendingConfirmation datatypes.JSON `json:"pending_confirmation,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// Message is a single message within a Session. Role follows the OpenAI
|
||||
// convention: system | user | assistant | tool. ToolCalls stores the
|
||||
// assistant's tool call payload (JSON) when present.
|
||||
type Message struct {
|
||||
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
SessionID string `gorm:"index;not null" json:"session_id"`
|
||||
Role string `gorm:"size:32;not null" json:"role"` // system | user | assistant | tool
|
||||
Content string `gorm:"type:text" json:"content"`
|
||||
ToolCalls datatypes.JSON `json:"tool_calls,omitempty"`
|
||||
ToolCallID string `gorm:"size:64" json:"tool_call_id,omitempty"` // for role=tool, the call id it answers
|
||||
Tokens int `gorm:"default:0" json:"tokens"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// AuditLog records security-relevant actions for traceability.
|
||||
type AuditLog struct {
|
||||
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"`
|
||||
AppID *int64 `gorm:"index" json:"app_id,omitempty"`
|
||||
SessionID *string `gorm:"index" json:"session_id,omitempty"`
|
||||
Actor string `gorm:"size:128" json:"actor"` // admin username, "system", app slug, ...
|
||||
Action string `gorm:"size:64;not null;index" json:"action"`
|
||||
Detail datatypes.JSON `json:"detail"`
|
||||
CreatedAt time.Time `gorm:"index" json:"created_at"`
|
||||
}
|
||||
Reference in New Issue
Block a user