Add database models and infrastructure for AI operation tracking and organization-level AI configuration. OperationLog model tracks all AI operations for auditing, including: - Operation type, tier, and trigger event - Token usage (input/output) - Status tracking (pending, success, failed, escalated) - Performance metrics (duration) - Rate limiting support via CountRecentOperations OrgAISettings model stores per-organization AI configuration: - Provider and model selection - Encrypted API key storage - Rate limits (max operations per hour) - Allowed operations whitelist - Agent mode permissions Also adds AI unit type to repository units for enabling/disabling AI features per repo.
128 lines
3.7 KiB
Go
128 lines
3.7 KiB
Go
// Copyright 2026 MarketAlly. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package setting
|
|
|
|
import (
|
|
"time"
|
|
|
|
"code.gitcaddy.com/server/v3/modules/log"
|
|
)
|
|
|
|
// AI settings for the GitCaddy AI service integration
|
|
var AI = struct {
|
|
Enabled bool
|
|
ServiceURL string
|
|
ServiceToken string
|
|
Timeout time.Duration
|
|
MaxRetries int
|
|
|
|
// Provider/model defaults (fallback when org doesn't configure)
|
|
DefaultProvider string
|
|
DefaultModel string
|
|
|
|
// System API keys (used when org/repo doesn't provide their own)
|
|
ClaudeAPIKey string
|
|
OpenAIAPIKey string
|
|
GeminiAPIKey string
|
|
|
|
// Rate limiting
|
|
MaxOperationsPerHour int
|
|
MaxTokensPerOperation int
|
|
|
|
// Feature gates (admin controls what's available)
|
|
EnableCodeReview bool
|
|
EnableIssueTriage bool
|
|
EnableDocGen bool
|
|
EnableExplainCode bool
|
|
EnableChat bool
|
|
AllowAutoRespond bool
|
|
AllowAutoReview bool
|
|
AllowAgentMode bool
|
|
|
|
// Content limits
|
|
MaxFileSizeKB int64
|
|
MaxDiffLines int
|
|
|
|
// Bot user
|
|
BotUserName string
|
|
}{
|
|
Enabled: false,
|
|
ServiceURL: "localhost:50051",
|
|
ServiceToken: "",
|
|
Timeout: 30 * time.Second,
|
|
MaxRetries: 3,
|
|
DefaultProvider: "claude",
|
|
DefaultModel: "claude-sonnet-4-20250514",
|
|
MaxOperationsPerHour: 100,
|
|
MaxTokensPerOperation: 8192,
|
|
EnableCodeReview: true,
|
|
EnableIssueTriage: true,
|
|
EnableDocGen: true,
|
|
EnableExplainCode: true,
|
|
EnableChat: true,
|
|
AllowAutoRespond: true,
|
|
AllowAutoReview: true,
|
|
AllowAgentMode: false,
|
|
MaxFileSizeKB: 500,
|
|
MaxDiffLines: 5000,
|
|
BotUserName: "gitcaddy-ai",
|
|
}
|
|
|
|
func loadAIFrom(rootCfg ConfigProvider) {
|
|
sec := rootCfg.Section("ai")
|
|
AI.Enabled = sec.Key("ENABLED").MustBool(false)
|
|
AI.ServiceURL = sec.Key("SERVICE_URL").MustString("localhost:50051")
|
|
AI.ServiceToken = sec.Key("SERVICE_TOKEN").MustString("")
|
|
AI.Timeout = sec.Key("TIMEOUT").MustDuration(30 * time.Second)
|
|
AI.MaxRetries = sec.Key("MAX_RETRIES").MustInt(3)
|
|
|
|
// Provider/model
|
|
AI.DefaultProvider = sec.Key("DEFAULT_PROVIDER").MustString("claude")
|
|
AI.DefaultModel = sec.Key("DEFAULT_MODEL").MustString("claude-sonnet-4-20250514")
|
|
|
|
// Validate provider
|
|
switch AI.DefaultProvider {
|
|
case "claude", "openai", "gemini":
|
|
// valid
|
|
default:
|
|
log.Error("[ai] DEFAULT_PROVIDER %q is not supported, falling back to claude", AI.DefaultProvider)
|
|
AI.DefaultProvider = "claude"
|
|
}
|
|
|
|
// System API keys
|
|
AI.ClaudeAPIKey = sec.Key("CLAUDE_API_KEY").MustString("")
|
|
AI.OpenAIAPIKey = sec.Key("OPENAI_API_KEY").MustString("")
|
|
AI.GeminiAPIKey = sec.Key("GEMINI_API_KEY").MustString("")
|
|
|
|
// Rate limiting
|
|
AI.MaxOperationsPerHour = sec.Key("MAX_OPERATIONS_PER_HOUR").MustInt(100)
|
|
AI.MaxTokensPerOperation = sec.Key("MAX_TOKENS_PER_OPERATION").MustInt(8192)
|
|
|
|
// Feature gates
|
|
AI.EnableCodeReview = sec.Key("ENABLE_CODE_REVIEW").MustBool(true)
|
|
AI.EnableIssueTriage = sec.Key("ENABLE_ISSUE_TRIAGE").MustBool(true)
|
|
AI.EnableDocGen = sec.Key("ENABLE_DOC_GEN").MustBool(true)
|
|
AI.EnableExplainCode = sec.Key("ENABLE_EXPLAIN_CODE").MustBool(true)
|
|
AI.EnableChat = sec.Key("ENABLE_CHAT").MustBool(true)
|
|
AI.AllowAutoRespond = sec.Key("ALLOW_AUTO_RESPOND").MustBool(true)
|
|
AI.AllowAutoReview = sec.Key("ALLOW_AUTO_REVIEW").MustBool(true)
|
|
AI.AllowAgentMode = sec.Key("ALLOW_AGENT_MODE").MustBool(false)
|
|
|
|
// Content limits
|
|
AI.MaxFileSizeKB = sec.Key("MAX_FILE_SIZE_KB").MustInt64(500)
|
|
AI.MaxDiffLines = sec.Key("MAX_DIFF_LINES").MustInt(5000)
|
|
|
|
// Bot user
|
|
AI.BotUserName = sec.Key("BOT_USER_NAME").MustString("gitcaddy-ai")
|
|
|
|
if AI.Enabled && AI.ServiceURL == "" {
|
|
log.Error("AI is enabled but SERVICE_URL is not configured")
|
|
AI.Enabled = false
|
|
}
|
|
|
|
if AI.Enabled {
|
|
log.Info("AI service integration enabled, connecting to %s", AI.ServiceURL)
|
|
}
|
|
}
|