Sourcegraph Cody

AI開発支援コードベース理解エンタープライズゼロデータ保持SOC2準拠

AIツール

Sourcegraph Cody

概要

Sourcegraph Codyは、コードベース理解に特化したAIコーディングアシスタントです。Claude Sonnet 4、GPT-4o等の最新LLMを活用し、VS Code、JetBrains、Web版で利用できます。業界最高レベルのコードベース全体理解能力を持ち、SOC2 Type II、GDPR、CCPA準拠によりエンタープライズ環境での高いセキュリティ要求に対応します。ゼロデータ保持・トレーニング無しポリシーにより、企業の機密コードを完全に保護します。

詳細

Sourcegraph Codyは、Sourcegraphの長年のコード検索・解析技術を基盤として開発されたAIアシスタントです。2024年版では、エンタープライズレベルのコードベース全体理解、高度な検索とシンボル解析、管理者権限とアクセス制御機能を強化し、大規模開発組織での使用に最適化されています。他のAIツールと比較して、コンテキスト認識の精度と深度で群を抜いており、複雑なコードベースでの開発効率を大幅に向上させます。

主要技術特徴

  • 業界最高レベルのコードベース理解: ファイル、クラス、関数間の関係を深く理解
  • ゼロデータ保持ポリシー: ユーザーコードの保存・学習・第三者共有を一切行わない
  • エンドツーエンド暗号化: 通信の完全暗号化によるセキュリティ確保
  • 最新LLM統合: Claude Sonnet 4、GPT-4o、Gemini Pro等をサポート
  • エンタープライズガバナンス: 細かなアクセス制御と管理者機能

最新機能(2024-2025年版)

  • Enhanced Context Engine: コードベース、ドキュメント、サービス間の関連性理解
  • Advanced Symbol Navigation: クラス、関数、変数の高精度な参照解析
  • Repository-wide Intelligence: プロジェクト全体を把握した的確な提案
  • Custom LLM Integration: 組織固有のLLMモデル連携サポート
  • Compliance Monitoring: リアルタイムでのセキュリティ・コンプライアンス監視

メリット・デメリット

メリット

  • 最強のコードベース理解: 業界で最も深いコンテキスト認識能力
  • 完全なプライバシー保護: ゼロデータ保持によるコード機密性の完全確保
  • エンタープライズ対応: SOC2、GDPR、CCPA準拠の包括的セキュリティ
  • 柔軟なLLM選択: 複数の最新LLMを用途に応じて選択可能
  • 高度な検索機能: コードベース内の効率的な情報検索
  • 管理機能: 組織レベルでの詳細なアクセス制御とガバナンス

デメリット

  • エンタープライズ機能中心: 個人開発者向け機能は他ツールより限定的
  • 学習コスト: 高度な機能を活用するには一定の学習が必要
  • 価格: エンタープライズ機能は月額15ドルと他より高価
  • セットアップ複雑性: 大規模組織での導入に専門知識が必要
  • 比較的新しいサービス: 市場実績はGitHub Copilot等より少ない

参考ページ

書き方の例

VS Codeでのセットアップ

# VS Code拡張機能のインストール
# 1. Extensions (Ctrl+Shift+X) を開く
# 2. "Sourcegraph Cody" を検索してインストール
# 3. Sourcegraphアカウントでサインイン
# 4. エンタープライズ環境では管理者による権限設定が必要

# コマンドラインでのインストール
code --install-extension sourcegraph.cody-ai

JetBrains IDEsでのセットアップ

# IntelliJ IDEA, PyCharm, WebStorm等での設定
# 1. Preferences > Plugins を開く
# 2. Marketplace で "Sourcegraph Cody" を検索
# 3. インストール後、IDEを再起動
# 4. Sourcegraphアカウントでログイン
# 5. エンタープライズ設定の確認

エンタープライズ環境での初期設定

# sourcegraph-config.yaml
# エンタープライズ環境でのCody設定例

enterprise:
  instance_url: "https://sourcegraph.company.com"
  access_token: "${SOURCEGRAPH_TOKEN}"
  
security:
  data_retention: "zero_day"
  encryption: "end_to_end"
  training_opt_out: true
  audit_logging: true
  
permissions:
  repository_access:
    - "company/main-app"
    - "company/api-service"
    - "company/shared-libraries"
  
  user_groups:
    developers:
      read_access: true
      chat_enabled: true
      autocomplete_enabled: true
    
    senior_developers:
      read_access: true
      chat_enabled: true
      autocomplete_enabled: true
      admin_features: true

compliance:
  frameworks: ["SOC2", "GDPR", "CCPA", "HIPAA"]
  monitoring: true
  reporting_enabled: true

Python でのコードベース理解活用

# Sourcegraph Cody による包括的なコードベース理解例
# 複雑なコードベースでの高精度な提案

import asyncio
import aiohttp
import json
from typing import Dict, List, Optional, Union
from dataclasses import dataclass
from datetime import datetime, timedelta

@dataclass
class UserProfile:
    """ユーザープロファイルデータクラス"""
    user_id: str
    username: str
    email: str
    created_at: datetime
    last_login: Optional[datetime] = None
    preferences: Dict[str, Union[str, bool, int]] = None

class DatabaseManager:
    """データベース接続と操作を管理するクラス"""
    
    def __init__(self, connection_string: str, pool_size: int = 10):
        # Codyがコードベース全体を理解して適切な初期化パターンを提案
        self.connection_string = connection_string
        self.pool_size = pool_size
        self.connection_pool = None
        self.logger = self._setup_logging()
    
    async def initialize_pool(self):
        """コネクションプール初期化"""
        # Codyが既存のDB設定パターンを理解して提案
        try:
            import asyncpg
            self.connection_pool = await asyncpg.create_pool(
                self.connection_string,
                min_size=1,
                max_size=self.pool_size,
                command_timeout=60,
                server_settings={
                    'jit': 'off'  # パフォーマンス最適化
                }
            )
            self.logger.info("Database connection pool initialized")
        except Exception as e:
            self.logger.error(f"Failed to initialize connection pool: {e}")
            raise

    async def get_user_profile(self, user_id: str) -> Optional[UserProfile]:
        """ユーザープロファイル取得"""
        # Codyがアプリケーション全体のUserProfile使用パターンを理解
        if not self.connection_pool:
            await self.initialize_pool()
        
        async with self.connection_pool.acquire() as connection:
            try:
                query = """
                SELECT user_id, username, email, created_at, last_login, preferences
                FROM user_profiles 
                WHERE user_id = $1 AND active = true
                """
                
                row = await connection.fetchrow(query, user_id)
                
                if not row:
                    return None
                
                # Codyがdataclass初期化パターンを提案
                return UserProfile(
                    user_id=row['user_id'],
                    username=row['username'],
                    email=row['email'],
                    created_at=row['created_at'],
                    last_login=row['last_login'],
                    preferences=json.loads(row['preferences']) if row['preferences'] else {}
                )
                
            except Exception as e:
                self.logger.error(f"Error fetching user profile {user_id}: {e}")
                return None

    async def update_user_preferences(self, user_id: str, preferences: Dict) -> bool:
        """ユーザー設定更新"""
        # 既存のupdate パターンをCodyが学習して提案
        if not self.connection_pool:
            await self.initialize_pool()
            
        async with self.connection_pool.acquire() as connection:
            try:
                # トランザクション内での安全な更新
                async with connection.transaction():
                    # 現在の設定を取得
                    current_prefs = await connection.fetchval(
                        "SELECT preferences FROM user_profiles WHERE user_id = $1",
                        user_id
                    )
                    
                    if current_prefs:
                        current_prefs = json.loads(current_prefs)
                        current_prefs.update(preferences)
                    else:
                        current_prefs = preferences
                    
                    # 更新実行
                    await connection.execute(
                        """
                        UPDATE user_profiles 
                        SET preferences = $2, updated_at = CURRENT_TIMESTAMP
                        WHERE user_id = $1
                        """,
                        user_id, json.dumps(current_prefs)
                    )
                    
                    # 監査ログ記録
                    await self._log_user_action(connection, user_id, "preferences_updated", preferences)
                    
                return True
                
            except Exception as e:
                self.logger.error(f"Error updating preferences for {user_id}: {e}")
                return False

class NotificationService:
    """通知サービスクラス"""
    
    def __init__(self, db_manager: DatabaseManager):
        # Codyが依存性注入パターンを理解
        self.db_manager = db_manager
        self.notification_channels = {
            'email': self._send_email,
            'push': self._send_push_notification,
            'sms': self._send_sms
        }
    
    async def send_user_notification(self, user_id: str, message: str, 
                                   channels: List[str] = None) -> Dict[str, bool]:
        """ユーザーへの通知送信"""
        # Codyがユーザーの設定に基づく通知ロジックを提案
        user_profile = await self.db_manager.get_user_profile(user_id)
        
        if not user_profile:
            return {"error": "User not found"}
        
        # ユーザー設定から通知チャンネルを決定
        if channels is None:
            channels = user_profile.preferences.get('notification_channels', ['email'])
        
        results = {}
        
        # 各チャンネルで通知送信
        for channel in channels:
            if channel in self.notification_channels:
                try:
                    success = await self.notification_channels[channel](user_profile, message)
                    results[channel] = success
                except Exception as e:
                    self.logger.error(f"Failed to send {channel} notification to {user_id}: {e}")
                    results[channel] = False
            else:
                results[channel] = False
        
        return results
    
    async def _send_email(self, user_profile: UserProfile, message: str) -> bool:
        """メール送信(プライベートメソッド)"""
        # Codyがメール送信パターンを組織のライブラリから学習
        try:
            # 組織固有のメールライブラリ使用パターンをCodyが提案
            from company_libs.email import EmailSender
            
            email_sender = EmailSender(
                smtp_host=self.config['smtp_host'],
                smtp_port=self.config['smtp_port'],
                use_tls=True
            )
            
            await email_sender.send_async(
                to_email=user_profile.email,
                subject="通知",
                body=message,
                template_name="default_notification"
            )
            
            return True
            
        except Exception as e:
            self.logger.error(f"Email sending failed: {e}")
            return False

class APIController:
    """REST API コントローラー"""
    
    def __init__(self, db_manager: DatabaseManager, notification_service: NotificationService):
        # Codyが既存のコントローラーパターンを学習
        self.db_manager = db_manager
        self.notification_service = notification_service
    
    async def handle_user_settings_update(self, request_data: Dict) -> Dict:
        """ユーザー設定更新APIエンドポイント"""
        # Codyがバリデーション、認証、レスポンスパターンを提案
        try:
            # リクエストバリデーション
            user_id = request_data.get('user_id')
            preferences = request_data.get('preferences', {})
            
            if not user_id:
                return {
                    "status": "error",
                    "message": "user_id is required",
                    "code": 400
                }
            
            # 設定更新実行
            success = await self.db_manager.update_user_preferences(user_id, preferences)
            
            if success:
                # 更新通知送信
                await self.notification_service.send_user_notification(
                    user_id, 
                    "設定が正常に更新されました",
                    channels=['email']
                )
                
                return {
                    "status": "success",
                    "message": "Preferences updated successfully",
                    "code": 200
                }
            else:
                return {
                    "status": "error",
                    "message": "Failed to update preferences",
                    "code": 500
                }
                
        except Exception as e:
            self.logger.error(f"Settings update error: {e}")
            return {
                "status": "error",
                "message": "Internal server error",
                "code": 500
            }

# 使用例とテスト
async def main():
    """メイン実行関数"""
    # Codyがアプリケーション全体の初期化パターンを理解
    db_manager = DatabaseManager("postgresql://user:pass@localhost/mydb")
    await db_manager.initialize_pool()
    
    notification_service = NotificationService(db_manager)
    api_controller = APIController(db_manager, notification_service)
    
    # テストデータで実行
    test_request = {
        "user_id": "user123",
        "preferences": {
            "notification_channels": ["email", "push"],
            "language": "ja",
            "theme": "dark"
        }
    }
    
    result = await api_controller.handle_user_settings_update(test_request)
    print(f"Update result: {result}")

if __name__ == "__main__":
    asyncio.run(main())

TypeScript でのプロジェクト横断的な理解

// TypeScript プロジェクトでのCody活用例
// 複数ファイル・モジュール間の関係を深く理解

// types/user.ts
export interface User {
    id: string;
    username: string;
    email: string;
    profile: UserProfile;
    permissions: Permission[];
    createdAt: Date;
    updatedAt: Date;
}

export interface UserProfile {
    firstName: string;
    lastName: string;
    avatar?: string;
    bio?: string;
    preferences: UserPreferences;
}

export interface UserPreferences {
    theme: 'light' | 'dark' | 'auto';
    language: string;
    notifications: NotificationSettings;
    privacy: PrivacySettings;
}

export interface Permission {
    resource: string;
    actions: string[];
    conditions?: Record<string, any>;
}

// services/UserService.ts
import { User, UserProfile, UserPreferences } from '../types/user';
import { DatabaseService } from './DatabaseService';
import { CacheService } from './CacheService';
import { NotificationService } from './NotificationService';

export class UserService {
    constructor(
        private db: DatabaseService,
        private cache: CacheService,
        private notifications: NotificationService
    ) {}

    async getUserById(userId: string): Promise<User | null> {
        // Codyが既存のキャッシングパターンを理解して提案
        const cacheKey = `user:${userId}`;
        
        // キャッシュから確認
        let user = await this.cache.get<User>(cacheKey);
        
        if (!user) {
            // データベースから取得
            user = await this.db.users.findById(userId, {
                include: ['profile', 'permissions']
            });
            
            if (user) {
                // キャッシュに保存(TTL: 1時間)
                await this.cache.set(cacheKey, user, 3600);
            }
        }
        
        return user;
    }

    async updateUserPreferences(
        userId: string, 
        preferences: Partial<UserPreferences>
    ): Promise<{ success: boolean; user?: User; error?: string }> {
        try {
            // Codyがトランザクション処理パターンを提案
            const result = await this.db.transaction(async (trx) => {
                // 現在のユーザー取得
                const currentUser = await trx.users.findById(userId);
                
                if (!currentUser) {
                    throw new Error('User not found');
                }
                
                // 設定更新
                const updatedPreferences = {
                    ...currentUser.profile.preferences,
                    ...preferences
                };
                
                // データベース更新
                const updatedUser = await trx.users.update(userId, {
                    'profile.preferences': updatedPreferences,
                    updatedAt: new Date()
                });
                
                // 監査ログ記録
                await trx.auditLogs.create({
                    userId,
                    action: 'preferences_updated',
                    changes: preferences,
                    timestamp: new Date()
                });
                
                return updatedUser;
            });
            
            // キャッシュ無効化
            await this.cache.delete(`user:${userId}`);
            
            // 通知送信(設定変更を他デバイスに通知)
            await this.notifications.sendToUser(userId, {
                type: 'preferences_updated',
                data: preferences
            });
            
            return { success: true, user: result };
            
        } catch (error) {
            console.error('Failed to update user preferences:', error);
            return { 
                success: false, 
                error: error instanceof Error ? error.message : 'Unknown error' 
            };
        }
    }

    async getUsersByPermission(permission: string): Promise<User[]> {
        // Codyが権限システムの関係を理解して効率的なクエリを提案
        const cacheKey = `users_by_permission:${permission}`;
        
        let users = await this.cache.get<User[]>(cacheKey);
        
        if (!users) {
            users = await this.db.users.findMany({
                where: {
                    permissions: {
                        some: {
                            resource: permission,
                            actions: {
                                hasAny: ['read', 'write', 'admin']
                            }
                        }
                    }
                },
                include: ['profile', 'permissions']
            });
            
            // 短期キャッシュ(権限情報は頻繁に変わる可能性)
            await this.cache.set(cacheKey, users, 300); // 5分
        }
        
        return users;
    }
}

// controllers/UserController.ts
import { Request, Response } from 'express';
import { UserService } from '../services/UserService';
import { validateUserPreferences } from '../validators/userValidators';
import { AuthMiddleware } from '../middleware/AuthMiddleware';

export class UserController {
    constructor(private userService: UserService) {}

    async updatePreferences(req: Request, res: Response): Promise<void> {
        try {
            // Codyが認証・認可パターンを理解
            const userId = req.user?.id;
            if (!userId) {
                res.status(401).json({ error: 'Unauthorized' });
                return;
            }
            
            // リクエストバリデーション
            const validationResult = validateUserPreferences(req.body);
            if (!validationResult.isValid) {
                res.status(400).json({ 
                    error: 'Invalid preferences data',
                    details: validationResult.errors 
                });
                return;
            }
            
            // 設定更新実行
            const result = await this.userService.updateUserPreferences(
                userId, 
                req.body
            );
            
            if (result.success) {
                res.json({
                    message: 'Preferences updated successfully',
                    user: result.user
                });
            } else {
                res.status(500).json({
                    error: 'Failed to update preferences',
                    details: result.error
                });
            }
            
        } catch (error) {
            console.error('Controller error:', error);
            res.status(500).json({ error: 'Internal server error' });
        }
    }

    async getProfile(req: Request, res: Response): Promise<void> {
        try {
            const userId = req.params.userId || req.user?.id;
            
            if (!userId) {
                res.status(400).json({ error: 'User ID required' });
                return;
            }
            
            // 権限チェック(自分のプロファイルまたは管理者権限)
            if (userId !== req.user?.id && !req.user?.permissions.includes('admin')) {
                res.status(403).json({ error: 'Insufficient permissions' });
                return;
            }
            
            const user = await this.userService.getUserById(userId);
            
            if (!user) {
                res.status(404).json({ error: 'User not found' });
                return;
            }
            
            // 機密情報を除外してレスポンス
            const safeUser = {
                id: user.id,
                username: user.username,
                email: user.email,
                profile: user.profile,
                // 権限情報は管理者のみ表示
                ...(req.user?.permissions.includes('admin') && { permissions: user.permissions })
            };
            
            res.json(safeUser);
            
        } catch (error) {
            console.error('Get profile error:', error);
            res.status(500).json({ error: 'Internal server error' });
        }
    }
}

React Hooks でのコンポーネント間連携

// React + TypeScript でのCody活用例
// コンポーネント間の状態管理と副作用を深く理解

import React, { useState, useEffect, useCallback, useContext, createContext } from 'react';
import { User, UserPreferences } from '../types/user';

// Context: ユーザー状態管理
interface UserContextType {
    user: User | null;
    updatePreferences: (preferences: Partial<UserPreferences>) => Promise<void>;
    loading: boolean;
    error: string | null;
}

const UserContext = createContext<UserContextType | undefined>(undefined);

// カスタムフック: ユーザー状態管理
export const useUser = (): UserContextType => {
    const context = useContext(UserContext);
    if (!context) {
        throw new Error('useUser must be used within UserProvider');
    }
    return context;
};

// プロバイダーコンポーネント
export const UserProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
    const [user, setUser] = useState<User | null>(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState<string | null>(null);

    // Codyが既存のAPI呼び出しパターンを理解して提案
    const fetchUser = useCallback(async () => {
        try {
            setLoading(true);
            setError(null);
            
            const response = await fetch('/api/user/profile', {
                credentials: 'include',
                headers: {
                    'Content-Type': 'application/json',
                }
            });
            
            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }
            
            const userData = await response.json();
            setUser(userData);
            
        } catch (err) {
            const errorMessage = err instanceof Error ? err.message : 'Unknown error';
            setError(errorMessage);
            console.error('Failed to fetch user:', err);
        } finally {
            setLoading(false);
        }
    }, []);

    const updatePreferences = useCallback(async (preferences: Partial<UserPreferences>) => {
        if (!user) {
            throw new Error('No user loaded');
        }

        try {
            setError(null);
            
            const response = await fetch('/api/user/preferences', {
                method: 'PUT',
                credentials: 'include',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify(preferences)
            });
            
            if (!response.ok) {
                throw new Error(`Failed to update preferences: ${response.status}`);
            }
            
            const updatedUser = await response.json();
            setUser(updatedUser.user);
            
        } catch (err) {
            const errorMessage = err instanceof Error ? err.message : 'Unknown error';
            setError(errorMessage);
            throw err;
        }
    }, [user]);

    // 初期ユーザー読み込み
    useEffect(() => {
        fetchUser();
    }, [fetchUser]);

    const value: UserContextType = {
        user,
        updatePreferences,
        loading,
        error
    };

    return (
        <UserContext.Provider value={value}>
            {children}
        </UserContext.Provider>
    );
};

// 設定コンポーネント
const UserPreferencesForm: React.FC = () => {
    const { user, updatePreferences, loading, error } = useUser();
    const [formData, setFormData] = useState<Partial<UserPreferences>>({});
    const [saving, setSaving] = useState(false);

    // Codyがフォーム状態管理パターンを提案
    useEffect(() => {
        if (user?.profile.preferences) {
            setFormData(user.profile.preferences);
        }
    }, [user]);

    const handleInputChange = useCallback((
        field: keyof UserPreferences,
        value: any
    ) => {
        setFormData(prev => ({
            ...prev,
            [field]: value
        }));
    }, []);

    const handleSubmit = useCallback(async (e: React.FormEvent) => {
        e.preventDefault();
        
        try {
            setSaving(true);
            await updatePreferences(formData);
            
            // 成功通知
            console.log('Preferences updated successfully');
            
        } catch (err) {
            console.error('Failed to save preferences:', err);
        } finally {
            setSaving(false);
        }
    }, [formData, updatePreferences]);

    if (loading) {
        return <div className="loading">ユーザー情報を読み込み中...</div>;
    }

    if (error) {
        return <div className="error">エラー: {error}</div>;
    }

    if (!user) {
        return <div className="error">ユーザー情報が見つかりません</div>;
    }

    return (
        <form onSubmit={handleSubmit} className="preferences-form">
            <h2>設定</h2>
            
            {/* テーマ設定 */}
            <div className="form-group">
                <label htmlFor="theme">テーマ</label>
                <select
                    id="theme"
                    value={formData.theme || 'light'}
                    onChange={(e) => handleInputChange('theme', e.target.value)}
                >
                    <option value="light">ライト</option>
                    <option value="dark">ダーク</option>
                    <option value="auto">自動</option>
                </select>
            </div>

            {/* 言語設定 */}
            <div className="form-group">
                <label htmlFor="language">言語</label>
                <select
                    id="language"
                    value={formData.language || 'ja'}
                    onChange={(e) => handleInputChange('language', e.target.value)}
                >
                    <option value="ja">日本語</option>
                    <option value="en">English</option>
                    <option value="zh">中文</option>
                </select>
            </div>

            {/* 通知設定 */}
            <div className="form-group">
                <h3>通知設定</h3>
                
                <label>
                    <input
                        type="checkbox"
                        checked={formData.notifications?.email || false}
                        onChange={(e) => handleInputChange('notifications', {
                            ...formData.notifications,
                            email: e.target.checked
                        })}
                    />
                    メール通知
                </label>
                
                <label>
                    <input
                        type="checkbox"
                        checked={formData.notifications?.push || false}
                        onChange={(e) => handleInputChange('notifications', {
                            ...formData.notifications,
                            push: e.target.checked
                        })}
                    />
                    プッシュ通知
                </label>
            </div>

            {/* 保存ボタン */}
            <button 
                type="submit" 
                disabled={saving}
                className="save-button"
            >
                {saving ? '保存中...' : '設定を保存'}
            </button>
        </form>
    );
};

// メインアプリケーション
const App: React.FC = () => {
    return (
        <UserProvider>
            <div className="app">
                <header className="app-header">
                    <h1>ユーザー設定アプリ</h1>
                </header>
                
                <main className="app-main">
                    <UserPreferencesForm />
                </main>
            </div>
        </UserProvider>
    );
};

export default App;

エンタープライズ設定とコンプライアンス

{
  "sourcegraph_cody": {
    "enterprise": {
      "instance_url": "https://sourcegraph.company.com",
      "authentication": {
        "method": "sso",
        "provider": "okta",
        "auto_refresh": true
      },
      "repository_access": {
        "allowed_repos": [
          "company/main-application",
          "company/shared-libraries",
          "company/api-services"
        ],
        "excluded_paths": [
          "*/secrets/*",
          "*.env",
          "*/config/production/*"
        ]
      }
    },
    "security": {
      "data_retention": "zero_day",
      "encryption": {
        "in_transit": "tls_1_3",
        "at_rest": "aes_256"
      },
      "audit_logging": {
        "enabled": true,
        "log_level": "comprehensive",
        "retention_days": 90
      },
      "compliance": {
        "frameworks": ["SOC2", "GDPR", "CCPA", "HIPAA"],
        "data_processing_agreement": true,
        "privacy_shield": true
      }
    },
    "ai_models": {
      "default": "claude-sonnet-4",
      "alternatives": ["gpt-4o", "gemini-pro"],
      "custom_models": {
        "enabled": true,
        "endpoints": [
          {
            "name": "company-internal-model",
            "url": "https://ai.company.com/v1",
            "auth_token": "${INTERNAL_AI_TOKEN}"
          }
        ]
      }
    },
    "permissions": {
      "admin_users": [
        "[email protected]",
        "[email protected]"
      ],
      "feature_access": {
        "chat": ["all_users"],
        "autocomplete": ["developers", "senior_developers"],
        "repository_search": ["senior_developers", "architects"],
        "admin_panel": ["admin_users"]
      },
      "rate_limits": {
        "chat_requests_per_hour": 100,
        "autocomplete_requests_per_minute": 60,
        "search_requests_per_hour": 200
      }
    },
    "monitoring": {
      "usage_analytics": true,
      "performance_monitoring": true,
      "error_reporting": true,
      "alerts": {
        "high_error_rate": {
          "threshold": "5%",
          "notification": "[email protected]"
        },
        "quota_exceeded": {
          "threshold": "90%",
          "notification": "[email protected]"
        }
      }
    }
  }
}