Files
calendar/packages/features/calAIPhone/providers/retellAI/services
Udit TakkarandGitHub 5c70060992 feat: voice and language support in cal.ai (#23865)
* feat: lang support

* fix: type errors

* feat: select voice agent

* refactor: address feedback

* refactor: address feedback

* refactor: missing import

* fix: types
2025-09-16 20:15:11 +05:30
..
2025-09-14 12:04:47 -03:00

RetellAI Services Architecture

This directory contains the refactored RetellAI services that follow the Single Responsibility Principle (SRP) to fix the previous GOD CLASS violation.

Architecture Overview

BEFORE: Single RetellAIService class (849 lines) handling all responsibilities AFTER: Focused services composed together (~150 lines each)

Services

1. AIConfigurationService

Responsibility: LLM and Agent configuration management

  • setupAIConfiguration() - Create LLM and Agent
  • deleteAIConfiguration() - Clean up AI resources
  • updateLLMConfiguration() - Update LLM settings
  • getLLMDetails() - Retrieve LLM information

2. AgentService

Responsibility: Agent CRUD operations

  • createAgent() - Create new agents
  • updateAgent() - Update agent properties
  • deleteAgent() - Remove agents
  • listAgents() - Get agent lists
  • getAgentWithDetails() - Get detailed agent info

3. BillingService

Responsibility: Stripe payments and subscriptions

  • generatePhoneNumberCheckoutSession() - Create Stripe checkout
  • cancelPhoneNumberSubscription() - Cancel subscriptions

4. CallService

Responsibility: Phone call operations

  • createPhoneCall() - Initiate calls
  • createTestCall() - Create test calls with credit validation

5. PhoneNumberService

Responsibility: Phone number management with transaction integrity

  • importPhoneNumber() - Import with compensating transactions
  • deletePhoneNumber() - Remove phone numbers
  • updatePhoneNumberWithAgents() - Assign agents
  • Includes billing leak protection and compensation failure handling

Usage Examples

Direct Service Usage (Advanced)

import {
  AIConfigurationService,
  AgentService,
  BillingService,
  CallService,
  PhoneNumberService
} from './services';

// Initialize dependencies
const repository = new RetellSDKClient({ apiKey: 'your-key' });
const agentRepository = new PrismaAgentRepositoryAdapter();
const phoneNumberRepository = new PrismaPhoneNumberRepositoryAdapter();
const transactionManager = new PrismaTransactionAdapter();

// Use individual services
const aiConfigService = new AIConfigurationService(repository);
const agentService = new AgentService(repository, agentRepository);
const billingService = new BillingService(phoneNumberRepository, repository);

// Setup AI configuration
const { llmId, agentId } = await aiConfigService.setupAIConfiguration({
  calApiKey: 'cal_live_123...',
  timeZone: 'America/New_York',
  eventTypeId: 12345,
});

// Create agent
const agent = await agentService.createAgent({
  name: 'Support Agent',
  userId: 1,
  userTimeZone: 'America/New_York',
  setupAIConfiguration: () => aiConfigService.setupAIConfiguration({...})
});
import { RetellAIService } from "../RetellAIService";

// Initialize main service
const service = new RetellAIService(repository, agentRepository, phoneNumberRepository, transactionManager);

// Use composed interface - same as before but internally organized
const { llmId, agentId } = await service.setupAIConfiguration({
  calApiKey: "cal_live_123...",
  timeZone: "America/New_York",
});

const phoneNumber = await service.importPhoneNumber({
  phone_number: "+1234567890",
  termination_uri: "https://example.com/webhook",
  userId: 1,
  agentId: "agent-123",
});

Benefits

Single Responsibility - Each service has one clear purpose
Easier Testing - Test services in isolation with focused mocks
Better Maintainability - Changes to billing don't affect phone operations
Reusability - Compose services differently for different use cases
Code Navigation - ~150 lines per service vs 849 lines
Backward Compatibility - Existing code continues to work

Testing

Each service can be tested independently:

// Test individual service
const aiConfigService = new AIConfigurationService(mockRepository);
await aiConfigService.setupAIConfiguration(config);

// Test main service with all composed services
const service = new RetellAIService(mockRepository, mockAgentRepo, mockPhoneRepo, mockTransaction);

Migration Guide

For new code: Use RetellAIService or individual services for specific needs For existing code: No changes needed - RetellAIService maintains same API

The refactoring eliminates the GOD CLASS antipattern while preserving all functionality and improving code organization.