2
0
Files
logikonline 26793bf898 feat(ai): add ai operation logging and org settings models
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.
2026-02-11 23:46:57 -05:00

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)
}
}