# Drupal AI Module Integration

## Overview

The `api_normalization` module now integrates with the `drupal/ai` module to provide a unified interface for AI provider operations. This integration leverages drupal/ai's plugin system while adding value-add features like failover, circuit breakers, and metrics collection.

## Architecture

```
┌─────────────────────────────────────────────┐
│     Application Code                        │
└──────────────────┬──────────────────────────┘
                   │
                   ▼
┌─────────────────────────────────────────────┐
│  AiProviderIntegration Service              │
│  (api_normalization wrapper)                │
└──────────────────┬──────────────────────────┘
                   │
                   ▼
┌─────────────────────────────────────────────┐
│  drupal/ai Plugin Manager                   │
│  - Provider plugins (Anthropic, OpenAI...)  │
│  - Operation types (Chat, Embeddings...)    │
└──────────────────┬──────────────────────────┘
                   │
                   ▼
┌─────────────────────────────────────────────┐
│  AI Provider APIs                            │
│  - Anthropic Claude                          │
│  - OpenAI GPT                                │
│  - Ollama (local)                            │
└─────────────────────────────────────────────┘
```

## Services

### AiProviderIntegration

**Service ID:** `api_normalization.ai_provider_integration`

Main service that wraps drupal/ai provider calls. Provides:

- Unified chat interface across all providers
- Provider availability checking
- Provider configuration management
- Response normalization

**Usage:**

```php
$integration = \Drupal::service('api_normalization.ai_provider_integration');

// Check if drupal/ai is available
if ($integration->isAvailable()) {
  // Execute a chat request
  $messages = [
    ['role' => 'user', 'content' => 'Hello, how are you?'],
  ];

  $response = $integration->chat($messages, 'anthropic', [
    'model' => 'claude-3-sonnet-20240229',
    'temperature' => 0.7,
    'max_tokens' => 1024,
  ]);

  // Response is normalized to OpenAI-compatible format
  $content = $response['choices'][0]['message']['content'];
}
```

### AiIntegrationService

**Service ID:** Not registered (use directly or via dependency injection)

Higher-level service that combines AI provider integration with additional features:

- AI-powered normalization
- Entity type classification
- Provider testing

**Usage:**

```php
use Drupal\api_normalization\Service\AiIntegrationService;

$ai_service = \Drupal::service(AiIntegrationService::class);

// Get available providers
$providers = $ai_service->getAvailableProviders();

// Test a provider
$is_working = $ai_service->testProvider('anthropic');

// Normalize data using AI
$normalized = $ai_service->normalizeWithAi($data);

// Classify entity type
$entity_type = $ai_service->classifyEntityType($data);
```

### AiNormalizerService

**Service ID:** `api_normalization.ai_normalizer`

Service for normalizing requests/responses across different AI providers. Now uses `AiProviderIntegration` for actual API calls.

**New Method:**

```php
$normalizer = \Drupal::service('api_normalization.ai_normalizer');

// Execute chat via drupal/ai
$messages = [
  ['role' => 'user', 'content' => 'Test message'],
];

$response = $normalizer->executeChat($messages, 'anthropic', [
  'model' => 'claude-3-sonnet',
  'max_tokens' => 500,
]);
```

**Legacy Methods (Deprecated):**

- `normalizeChatRequest()` - Still works but use `executeChat()` instead
- `normalizeChatResponse()` - Use for response format conversion only

## Event Subscriber

### AiProviderEventSubscriber

**Service ID:** `api_normalization.ai_provider_event_subscriber`

Subscribes to AI module events for:

- Logging AI requests and responses
- Collecting metrics (request count, duration, errors)
- Performance monitoring

Events are automatically captured when using the integration services.

## Configuration

### Default Provider

Set the default AI provider in configuration:

```yaml
# config/api_normalization.settings.yml
default_ai_provider: anthropic
```

Or via UI:
1. Navigate to `/admin/config/api-normalization/settings`
2. Set "Default AI Provider"
3. Save configuration

### Provider-Specific Settings

Provider credentials and settings are managed by the `drupal/ai` module:

1. Install AI module: `composer require drupal/ai:^1.0`
2. Enable AI module: `drush en ai`
3. Configure providers: `/admin/config/ai/providers`

## Features

### Unified Chat Interface

All providers (Anthropic, OpenAI, Ollama) use the same interface:

```php
$response = $integration->chat($messages, $provider, $config);
```

Response format is normalized to OpenAI-compatible structure:

```php
[
  'choices' => [
    [
      'message' => [
        'role' => 'assistant',
        'content' => 'Response text...',
      ],
      'finish_reason' => 'stop',
    ],
  ],
  'usage' => [
    'prompt_tokens' => 100,
    'completion_tokens' => 50,
    'total_tokens' => 150,
  ],
]
```

### Provider Failover

Combine with `ProviderFailoverService` for automatic failover:

```php
$failover = \Drupal::service('api_normalization.provider_failover');

$response = $failover->executeWithFailover('anthropic', function($provider_id) use ($messages) {
  $integration = \Drupal::service('api_normalization.ai_provider_integration');
  return $integration->chat($messages, $provider_id);
});
```

### Metrics Collection

All AI requests are automatically tracked:

```php
$metrics = \Drupal::service('api_normalization.metrics');

// Get AI request metrics
$stats = $metrics->getMetricsByType('ai_request_completed');
```

## Testing

### Provider Testing

Test if a provider is accessible:

```php
$integration = \Drupal::service('api_normalization.ai_provider_integration');

// Test Anthropic
if ($integration->testProvider('anthropic')) {
  // Provider is working
}

// Test OpenAI
if ($integration->testProvider('openai')) {
  // Provider is working
}
```

### Unit Tests

Run kernel tests:

```bash
vendor/bin/phpunit tests/src/Kernel/AiProviderIntegrationTest.php
```

## Migration from Direct AI Module Usage

### Before (Direct drupal/ai usage)

```php
$ai_provider = \Drupal::service('plugin.manager.ai_provider')
  ->createInstance('anthropic');

$chat_messages = [/* ... */];
$chat_input = new ChatInput($chat_messages);
$response = $ai_provider->chat($chat_input);
```

### After (Via api_normalization integration)

```php
$integration = \Drupal::service('api_normalization.ai_provider_integration');

$messages = [
  ['role' => 'user', 'content' => 'Hello'],
];

$response = $integration->chat($messages, 'anthropic');
```

**Benefits:**

1. Unified interface (no need to create ChatInput objects)
2. Automatic response normalization
3. Built-in metrics and logging
4. Failover support
5. Circuit breaker protection

## Dependencies

- `drupal/core: ^10.3 || ^11`
- `drupal/ai: ^1.0` (required)
- `drupal/key: ^1.17` (required for secure key storage)

## See Also

- [drupal/ai module documentation](https://www.drupal.org/project/ai)
- [Provider Failover Guide](./provider-failover.md)
- [Circuit Breaker Pattern](./circuit-breaker.md)
- [API Normalization Architecture](../architecture/overview.md)
