// Copyright 2026 The MokoGitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package ai import ( "context" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db" "code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/timeutil" ) // OrgSetting stores AI configuration for an organization. type OrgSetting struct { ID int64 `xorm:"pk autoincr"` OrgID int64 `xorm:"UNIQUE NOT NULL"` Enabled bool `xorm:"NOT NULL DEFAULT true"` APIKeyEncrypted string `xorm:"TEXT"` Model string `xorm:"VARCHAR(50) NOT NULL DEFAULT 'claude-sonnet-4-6'"` RateLimitRequests int `xorm:"NOT NULL DEFAULT 100"` RateLimitTokensMonth int64 `xorm:"NOT NULL DEFAULT 5000000"` CreatedUnix timeutil.TimeStamp UpdatedUnix timeutil.TimeStamp } func init() { db.RegisterModel(new(OrgSetting)) db.RegisterModel(new(RepoSetting)) db.RegisterModel(new(UsageLog)) } // TableName returns the table name for OrgSetting. func (OrgSetting) TableName() string { return "ai_org_setting" } // RepoSetting stores AI configuration for a repository. type RepoSetting struct { ID int64 `xorm:"pk autoincr"` RepoID int64 `xorm:"UNIQUE NOT NULL"` Enabled bool `xorm:"NOT NULL DEFAULT true"` AutoReview bool `xorm:"NOT NULL DEFAULT true"` Strictness string `xorm:"VARCHAR(20) NOT NULL DEFAULT 'standard'"` IgnorePatterns string `xorm:"TEXT"` CreatedUnix timeutil.TimeStamp UpdatedUnix timeutil.TimeStamp } // TableName returns the table name for RepoSetting. func (RepoSetting) TableName() string { return "ai_repo_setting" } // UsageLog records AI token usage per action. type UsageLog struct { ID int64 `xorm:"pk autoincr"` OrgID int64 `xorm:"INDEX NOT NULL"` RepoID int64 `xorm:"INDEX NOT NULL"` TriggeredByID int64 ActionType string `xorm:"VARCHAR(20) NOT NULL"` // review, chat, agent Model string `xorm:"VARCHAR(50)"` TokensInput int64 TokensOutput int64 DurationMs int64 CreatedUnix timeutil.TimeStamp `xorm:"INDEX"` } // TableName returns the table name for UsageLog. func (UsageLog) TableName() string { return "ai_usage_log" } // GetOrgSetting returns the AI settings for an org, or nil if not configured. func GetOrgSetting(ctx context.Context, orgID int64) (*OrgSetting, error) { setting := &OrgSetting{OrgID: orgID} has, err := db.GetEngine(ctx).Where("org_id = ?", orgID).Get(setting) if err != nil { return nil, err } if !has { return nil, nil } return setting, nil } // GetRepoSetting returns the AI settings for a repo, or nil if not configured. func GetRepoSetting(ctx context.Context, repoID int64) (*RepoSetting, error) { setting := &RepoSetting{RepoID: repoID} has, err := db.GetEngine(ctx).Where("repo_id = ?", repoID).Get(setting) if err != nil { return nil, err } if !has { return nil, nil } return setting, nil } // CreateOrgSetting inserts a new org AI setting. func CreateOrgSetting(ctx context.Context, setting *OrgSetting) error { setting.CreatedUnix = timeutil.TimeStampNow() setting.UpdatedUnix = timeutil.TimeStampNow() _, err := db.GetEngine(ctx).Insert(setting) return err } // UpdateOrgSetting updates an existing org AI setting. func UpdateOrgSetting(ctx context.Context, setting *OrgSetting) error { setting.UpdatedUnix = timeutil.TimeStampNow() _, err := db.GetEngine(ctx).ID(setting.ID).AllCols().Update(setting) return err } // CreateRepoSetting inserts a new repo AI setting. func CreateRepoSetting(ctx context.Context, setting *RepoSetting) error { setting.CreatedUnix = timeutil.TimeStampNow() setting.UpdatedUnix = timeutil.TimeStampNow() _, err := db.GetEngine(ctx).Insert(setting) return err } // UpdateRepoSetting updates an existing repo AI setting. func UpdateRepoSetting(ctx context.Context, setting *RepoSetting) error { setting.UpdatedUnix = timeutil.TimeStampNow() _, err := db.GetEngine(ctx).ID(setting.ID).AllCols().Update(setting) return err } // LogUsage records an AI usage event. func LogUsage(ctx context.Context, log *UsageLog) error { log.CreatedUnix = timeutil.TimeStampNow() _, err := db.GetEngine(ctx).Insert(log) return err }