# Multi-Provider AI Architecture for Arc CLI

## Overview
Arc CLI implements a provider-agnostic architecture that supports multiple AI providers (Google Gemini, OpenAI GPT, Anthropic Claude, etc.) to avoid vendor lock-in and provide users with choice.

## Core Architecture

### 1. Provider Abstraction Layer
```typescript
// packages/core/src/providers/types.ts
export interface AIProvider {
  name: string;
  execute(prompt: string, options?: ProviderOptions): Promise<ProviderResponse>;
  getModels(): Promise<ModelInfo[]>;
  checkLimits(): Promise<UsageLimits>;
}

export interface ProviderOptions {
  model?: string;
  temperature?: number;
  maxTokens?: number;
  stream?: boolean;
}

export interface ProviderResponse {
  text: string;
  usage: TokenUsage;
  model: string;
  finishReason: string;
}
```

### 2. Provider Registry
```typescript
// packages/core/src/providers/registry.ts
export class ProviderRegistry {
  private providers = new Map<string, AIProvider>();

  register(provider: AIProvider): void {
    this.providers.set(provider.name, provider);
  }

  getProvider(name: string): AIProvider | undefined {
    return this.providers.get(name);
  }

  getAvailableProviders(): string[] {
    return Array.from(this.providers.keys());
  }

  getDefaultProvider(): AIProvider {
    // Return user's preferred provider or first available
    return this.providers.get('openai') || this.providers.values().next().value;
  }
}
```

### 3. Provider Implementations

#### OpenAI Provider
```typescript
// packages/core/src/providers/openai.ts
import OpenAI from 'openai';

export class OpenAIProvider implements AIProvider {
  name = 'openai';
  private client: OpenAI;

  constructor(apiKey: string) {
    this.client = new OpenAI({ apiKey });
  }

  async execute(prompt: string, options?: ProviderOptions): Promise<ProviderResponse> {
    const completion = await this.client.chat.completions.create({
      model: options?.model || 'gpt-4',
      messages: [{ role: 'user', content: prompt }],
      temperature: options?.temperature || 0.7,
      max_tokens: options?.maxTokens,
      stream: options?.stream,
    });

    return {
      text: completion.choices[0].message.content || '',
      usage: {
        promptTokens: completion.usage?.prompt_tokens || 0,
        completionTokens: completion.usage?.completion_tokens || 0,
        totalTokens: completion.usage?.total_tokens || 0,
      },
      model: completion.model,
      finishReason: completion.choices[0].finish_reason || 'stop',
    };
  }

  async getModels(): Promise<ModelInfo[]> {
    const models = await this.client.models.list();
    return models.data.map(model => ({
      id: model.id,
      name: model.id,
      provider: 'openai',
      contextWindow: this.getContextWindow(model.id),
    }));
  }

  async checkLimits(): Promise<UsageLimits> {
    // Implement usage checking logic
    return {
      requestsPerMinute: 60,
      requestsPerDay: 1000,
      tokensPerMinute: 10000,
      tokensPerDay: 100000,
    };
  }

  private getContextWindow(modelId: string): number {
    const contextWindows: Record<string, number> = {
      'gpt-4': 8192,
      'gpt-4-turbo': 128000,
      'gpt-4o': 128000,
      'gpt-3.5-turbo': 16385,
    };
    return contextWindows[modelId] || 4096;
  }
}
```

#### Anthropic Provider
```typescript
// packages/core/src/providers/anthropic.ts
import Anthropic from '@anthropic-ai/sdk';

export class AnthropicProvider implements AIProvider {
  name = 'anthropic';
  private client: Anthropic;

  constructor(apiKey: string) {
    this.client = new Anthropic({ apiKey });
  }

  async execute(prompt: string, options?: ProviderOptions): Promise<ProviderResponse> {
    const message = await this.client.messages.create({
      model: options?.model || 'claude-3-sonnet-20240229',
      max_tokens: options?.maxTokens || 4096,
      temperature: options?.temperature || 0.7,
      messages: [{ role: 'user', content: prompt }],
    });

    return {
      text: message.content[0].type === 'text' ? message.content[0].text : '',
      usage: {
        promptTokens: message.usage.input_tokens,
        completionTokens: message.usage.output_tokens,
        totalTokens: message.usage.input_tokens + message.usage.output_tokens,
      },
      model: message.model,
      finishReason: message.stop_reason || 'stop',
    };
  }

  async getModels(): Promise<ModelInfo[]> {
    // Anthropic doesn't have a models API, return known models
    return [
      {
        id: 'claude-3-opus-20240229',
        name: 'Claude 3 Opus',
        provider: 'anthropic',
        contextWindow: 200000,
      },
      {
        id: 'claude-3-sonnet-20240229',
        name: 'Claude 3 Sonnet',
        provider: 'anthropic',
        contextWindow: 200000,
      },
      {
        id: 'claude-3-haiku-20240307',
        name: 'Claude 3 Haiku',
        provider: 'anthropic',
        contextWindow: 200000,
      },
    ];
  }

  async checkLimits(): Promise<UsageLimits> {
    // Implement usage checking
    return {
      requestsPerMinute: 50,
      requestsPerDay: 1000,
      tokensPerMinute: 50000,
      tokensPerDay: 200000,
    };
  }
}
```

#### Google Gemini Provider (Existing)
```typescript
// packages/core/src/providers/gemini.ts
import { GoogleGenerativeAI } from '@google/generative-ai';

export class GeminiProvider implements AIProvider {
  name = 'gemini';
  private client: GoogleGenerativeAI;

  constructor(apiKey: string) {
    this.client = new GoogleGenerativeAI(apiKey);
  }

  async execute(prompt: string, options?: ProviderOptions): Promise<ProviderResponse> {
    const model = this.client.getGenerativeModel({
      model: options?.model || 'gemini-pro'
    });

    const result = await model.generateContent(prompt);
    const response = result.response;

    return {
      text: response.text(),
      usage: {
        promptTokens: response.usageMetadata?.promptTokenCount || 0,
        completionTokens: response.usageMetadata?.candidatesTokenCount || 0,
        totalTokens: response.usageMetadata?.totalTokenCount || 0,
      },
      model: options?.model || 'gemini-pro',
      finishReason: 'stop',
    };
  }

  async getModels(): Promise<ModelInfo[]> {
    // Gemini doesn't have a models API, return known models
    return [
      {
        id: 'gemini-pro',
        name: 'Gemini Pro',
        provider: 'gemini',
        contextWindow: 32768,
      },
      {
        id: 'gemini-pro-vision',
        name: 'Gemini Pro Vision',
        provider: 'gemini',
        contextWindow: 16384,
      },
    ];
  }

  async checkLimits(): Promise<UsageLimits> {
    return {
      requestsPerMinute: 60,
      requestsPerDay: 1000,
      tokensPerMinute: 10000,
      tokensPerDay: 100000,
    };
  }
}
```

### 4. Provider Configuration
```typescript
// packages/core/src/config/providers.ts
export interface ProviderConfig {
  name: string;
  apiKey: string;
  enabled: boolean;
  priority: number; // For fallback ordering
  models: {
    default: string;
    allowed: string[];
  };
  limits: {
    requestsPerMinute: number;
    requestsPerDay: number;
    tokensPerMinute: number;
    tokensPerDay: number;
  };
}

export const defaultProviderConfigs: ProviderConfig[] = [
  {
    name: 'openai',
    apiKey: process.env['OPENAI_API_KEY'] || '',
    enabled: true,
    priority: 1,
    models: {
      default: 'gpt-4',
      allowed: ['gpt-4', 'gpt-4-turbo', 'gpt-3.5-turbo'],
    },
    limits: {
      requestsPerMinute: 60,
      requestsPerDay: 1000,
      tokensPerMinute: 10000,
      tokensPerDay: 100000,
    },
  },
  {
    name: 'anthropic',
    apiKey: process.env['ANTHROPIC_API_KEY'] || '',
    enabled: true,
    priority: 2,
    models: {
      default: 'claude-3-sonnet-20240229',
      allowed: ['claude-3-opus-20240229', 'claude-3-sonnet-20240229', 'claude-3-haiku-20240307'],
    },
    limits: {
      requestsPerMinute: 50,
      requestsPerDay: 1000,
      tokensPerMinute: 50000,
      tokensPerDay: 200000,
    },
  },
  {
    name: 'gemini',
    apiKey: process.env['GEMINI_API_KEY'] || '',
    enabled: true,
    priority: 3,
    models: {
      default: 'gemini-pro',
      allowed: ['gemini-pro', 'gemini-pro-vision'],
    },
    limits: {
      requestsPerMinute: 60,
      requestsPerDay: 1000,
      tokensPerMinute: 10000,
      tokensPerDay: 100000,
    },
  },
];
```

### 5. Provider Manager
```typescript
// packages/core/src/providers/manager.ts
export class ProviderManager {
  private registry: ProviderRegistry;
  private config: ProviderConfig[];

  constructor(config: ProviderConfig[]) {
    this.registry = new ProviderRegistry();
    this.config = config;
    this.initializeProviders();
  }

  private initializeProviders(): void {
    for (const providerConfig of this.config) {
      if (!providerConfig.enabled || !providerConfig.apiKey) {
        continue;
      }

      let provider: AIProvider;

      switch (providerConfig.name) {
        case 'openai':
          provider = new OpenAIProvider(providerConfig.apiKey);
          break;
        case 'anthropic':
          provider = new AnthropicProvider(providerConfig.apiKey);
          break;
        case 'gemini':
          provider = new GeminiProvider(providerConfig.apiKey);
          break;
        default:
          console.warn(`Unknown provider: ${providerConfig.name}`);
          continue;
      }

      this.registry.register(provider);
    }
  }

  async executeWithFallback(prompt: string, options?: ProviderOptions): Promise<ProviderResponse> {
    const providers = this.getProvidersByPriority();

    for (const provider of providers) {
      try {
        // Check rate limits
        const limits = await provider.checkLimits();
        if (this.isRateLimited(limits)) {
          continue; // Try next provider
        }

        return await provider.execute(prompt, options);
      } catch (error) {
        console.warn(`Provider ${provider.name} failed:`, error);
        continue; // Try next provider
      }
    }

    throw new Error('All providers failed or rate limited');
  }

  private getProvidersByPriority(): AIProvider[] {
    const providers = this.registry.getAvailableProviders()
      .map(name => this.registry.getProvider(name)!)
      .sort((a, b) => {
        const aConfig = this.config.find(c => c.name === a.name);
        const bConfig = this.config.find(c => c.name === b.name);
        return (aConfig?.priority || 999) - (bConfig?.priority || 999);
      });

    return providers;
  }

  private isRateLimited(limits: UsageLimits): boolean {
    // Implement rate limiting logic
    // This would track actual usage and compare against limits
    return false; // Placeholder
  }
}
```

### 6. Integration with ARC-Agents
```typescript
// Update ArcAgentTrigger to use ProviderManager
export class ArcAgentTrigger {
  constructor(private providerManager: ProviderManager) {}

  async executeAgent(agentName: string, prompt: string): Promise<string> {
    // Load agent config to determine preferred provider
    const config = await this.loadAgentConfig(agentName);
    const providerName = config.preferredProvider || 'auto';

    const options: ProviderOptions = {
      model: config.model,
      temperature: config.temperature || 0.7,
      maxTokens: config.maxTokens,
    };

    if (providerName === 'auto') {
      // Use provider manager with fallback
      const response = await this.providerManager.executeWithFallback(prompt, options);
      return response.text;
    } else {
      // Use specific provider
      const provider = this.providerManager.getProvider(providerName);
      if (!provider) {
        throw new Error(`Provider ${providerName} not available`);
      }
      const response = await provider.execute(prompt, options);
      return response.text;
    }
  }
}
```

### 7. CLI Commands for Provider Management
```typescript
// Add to ArcAgentsCommandLoader
private createProviderCommands(): SlashCommand[] {
  return [
    {
      name: 'providers-list',
      description: 'List available AI providers',
      execute: async () => {
        const providers = this.providerManager.getAvailableProviders();
        return `Available providers: ${providers.join(', ')}`;
      }
    },
    {
      name: 'provider-switch',
      description: 'Switch to a different AI provider',
      execute: async (args: readonly string[]) => {
        const providerName = args[0];
        // Implement provider switching logic
        return `Switched to provider: ${providerName}`;
      }
    },
    {
      name: 'provider-status',
      description: 'Check provider status and limits',
      execute: async () => {
        // Implement status checking
        return 'Provider status information';
      }
    }
  ];
}
```

## Benefits of Multi-Provider Architecture

### ✅ Avoid Vendor Lock-in
- Users can switch between providers based on needs, pricing, or availability
- No dependency on single AI provider ecosystem
- Future-proof as new providers emerge

### ✅ Optimal Provider Selection
- Automatic fallback when providers are rate-limited
- Model selection based on task requirements
- Cost optimization across providers

### ✅ Enhanced Reliability
- Redundant providers ensure service availability
- Graceful degradation when providers fail
- Load balancing across multiple providers

### ✅ Performance Optimization
- Choose providers based on speed, quality, or cost
- Context window optimization per provider
- Specialized model selection for different tasks

### ✅ User Choice & Flexibility
- Users can configure preferred providers
- Per-agent provider preferences
- Custom model selection and parameters

## Configuration Example

```json
{
  "providers": {
    "openai": {
      "apiKey": "${OPENAI_API_KEY}",
      "enabled": true,
      "priority": 1,
      "models": {
        "default": "gpt-4",
        "allowed": ["gpt-4", "gpt-4-turbo", "gpt-3.5-turbo"]
      }
    },
    "anthropic": {
      "apiKey": "${ANTHROPIC_API_KEY}",
      "enabled": true,
      "priority": 2,
      "models": {
        "default": "claude-3-sonnet-20240229",
        "allowed": ["claude-3-opus-20240229", "claude-3-sonnet-20240229"]
      }
    },
    "gemini": {
      "apiKey": "${GEMINI_API_KEY}",
      "enabled": true,
      "priority": 3,
      "models": {
        "default": "gemini-pro",
        "allowed": ["gemini-pro", "gemini-pro-vision"]
      }
    }
  },
  "agents": {
    "projectOrchestrator": {
      "preferredProvider": "auto",
      "model": "gpt-4",
      "temperature": 0.3
    },
    "codeReviewer": {
      "preferredProvider": "claude-3-sonnet-20240229",
      "model": "claude-3-sonnet-20240229",
      "temperature": 0.1
    }
  }
}
```

This multi-provider architecture transforms Arc CLI from a single-vendor tool into a flexible, resilient AI platform that can leverage the best capabilities from multiple AI providers while maintaining ARC-Agents autonomous orchestration features.