Implementation Examples

Real-world examples and code samples for integrating PromptCompose SDK

SDK Implementation Examples

This guide provides practical examples of implementing the PromptCompose SDK in various frameworks and use cases.

Basic Usage Examples

Simple Prompt Resolution

import { PromptCompose } from '@promptcompose/sdk';

const promptCompose = new PromptCompose(
  process.env.PROMPT_COMPOSE_API_KEY!,
  process.env.PROMPT_COMPOSE_PROJECT_ID!
);

async function getWelcomeMessage(userName: string): Promise<string> {
  try {
    await promptCompose.init();
    
    const result = await promptCompose.resolvePrompt('welcome-prompt', undefined, {
      userName: userName,
      currentDate: new Date().toLocaleDateString()
    });
    
    return result.content;
  } catch (error) {
    console.error('Failed to get welcome message:', error);
    return `Welcome, ${userName}!`; // Fallback
  }
}

// Usage
const message = await getWelcomeMessage('John Doe');
console.log(message);

A/B Testing Example

async function getPersonalizedMessage(userId: string, userName: string) {
  const result = await promptCompose.resolvePrompt('personalized-greeting', {
    config: {
      abTesting: {
        sessionId: `user-${userId}`
      }
    }
  }, {
    userName: userName
  });

  // Track which variant was served
  if (result.variant) {
    console.log(`User ${userId} saw variant: ${result.variant.name}`);
    
    // Store for conversion tracking
    return {
      content: result.content,
      testId: result.abTest?.publicId,
      variantId: result.variant.publicId
    };
  }

  return { content: result.content };
}

// Report conversion when user performs desired action
async function reportSuccess(testId: string, variantId: string, userId: string) {
  await promptCompose.reportABResult(testId, {
    variantId: variantId,
    status: 'success',
    sessionId: `user-${userId}`
  });
}

Framework Integration Examples

React Application

Custom Hook

// hooks/usePromptCompose.ts
import { useState, useEffect, useCallback } from 'react';
import { PromptCompose } from '@promptcompose/sdk';

interface UsePromptComposeReturn {
  resolvePrompt: (id: string, variables?: any) => Promise<string>;
  loading: boolean;
  error: string | null;
}

export function usePromptCompose(): UsePromptComposeReturn {
  const [sdk, setSdk] = useState<PromptCompose | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const initSDK = async () => {
      try {
        const promptCompose = new PromptCompose(
          process.env.REACT_APP_PROMPT_COMPOSE_API_KEY!,
          process.env.REACT_APP_PROMPT_COMPOSE_PROJECT_ID!
        );
        
        await promptCompose.init();
        setSdk(promptCompose);
      } catch (err) {
        setError(err instanceof Error ? err.message : 'Initialization failed');
      }
    };

    initSDK();
  }, []);

  const resolvePrompt = useCallback(async (
    promptId: string, 
    variables?: any
  ): Promise<string> => {
    if (!sdk) throw new Error('SDK not initialized');
    
    setLoading(true);
    setError(null);
    
    try {
      const result = await sdk.resolvePrompt(promptId, undefined, variables);
      return result.content;
    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      setError(errorMessage);
      throw err;
    } finally {
      setLoading(false);
    }
  }, [sdk]);

  return { resolvePrompt, loading, error };
}

Component Usage

// components/WelcomeMessage.tsx
import React, { useEffect, useState } from 'react';
import { usePromptCompose } from '../hooks/usePromptCompose';

interface WelcomeMessageProps {
  userId: string;
  userName: string;
}

export function WelcomeMessage({ userId, userName }: WelcomeMessageProps) {
  const { resolvePrompt, loading, error } = usePromptCompose();
  const [message, setMessage] = useState<string>('');

  useEffect(() => {
    const fetchMessage = async () => {
      try {
        const content = await resolvePrompt('welcome-message', {
          userId,
          userName,
          timestamp: Date.now()
        });
        setMessage(content);
      } catch (error) {
        console.error('Failed to fetch welcome message:', error);
        setMessage(`Welcome, ${userName}!`);
      }
    };

    fetchMessage();
  }, [userId, userName, resolvePrompt]);

  if (loading) {
    return <div className="loading">Loading message...</div>;
  }

  if (error) {
    return <div className="error">Failed to load message</div>;
  }

  return (
    <div className="welcome-message">
      {message}
    </div>
  );
}

Context Provider

// context/PromptComposeContext.tsx
import React, { createContext, useContext, useEffect, useState } from 'react';
import { PromptCompose } from '@promptcompose/sdk';

interface PromptComposeContextType {
  sdk: PromptCompose | null;
  isReady: boolean;
  error: string | null;
}

const PromptComposeContext = createContext<PromptComposeContextType>({
  sdk: null,
  isReady: false,
  error: null
});

export function PromptComposeProvider({ children }: { children: React.ReactNode }) {
  const [sdk, setSdk] = useState<PromptCompose | null>(null);
  const [isReady, setIsReady] = useState(false);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const initSDK = async () => {
      try {
        const promptCompose = new PromptCompose(
          process.env.REACT_APP_PROMPT_COMPOSE_API_KEY!,
          process.env.REACT_APP_PROMPT_COMPOSE_PROJECT_ID!
        );
        
        await promptCompose.init();
        setSdk(promptCompose);
        setIsReady(true);
      } catch (err) {
        setError(err instanceof Error ? err.message : 'Initialization failed');
      }
    };

    initSDK();
  }, []);

  return (
    <PromptComposeContext.Provider value={{ sdk, isReady, error }}>
      {children}
    </PromptComposeContext.Provider>
  );
}

export function usePromptComposeContext() {
  const context = useContext(PromptComposeContext);
  if (!context) {
    throw new Error('usePromptComposeContext must be used within PromptComposeProvider');
  }
  return context;
}

Next.js Integration

API Route

// pages/api/prompts/[id].ts
import { NextApiRequest, NextApiResponse } from 'next';
import { PromptCompose } from '@promptcompose/sdk';

const promptCompose = new PromptCompose(
  process.env.PROMPT_COMPOSE_API_KEY!,
  process.env.PROMPT_COMPOSE_PROJECT_ID!
);

// Initialize once when the API route is first loaded
let initialized = false;

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  if (!initialized) {
    await promptCompose.init();
    initialized = true;
  }

  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method not allowed' });
  }

  const { id } = req.query;
  const { variables, config, sessionId } = req.body;

  try {
    const result = await promptCompose.resolvePrompt(
      id as string,
      config || {
        config: {
          abTesting: { sessionId }
        }
      },
      variables
    );

    res.status(200).json({
      content: result.content,
      variant: result.variant?.name,
      test: result.abTest?.name
    });
  } catch (error) {
    console.error('Prompt resolution failed:', error);
    res.status(500).json({ 
      error: error instanceof Error ? error.message : 'Unknown error' 
    });
  }
}

Client-side Usage

// lib/prompts.ts
export async function resolvePrompt(
  promptId: string, 
  variables?: any, 
  sessionId?: string
) {
  const response = await fetch(`/api/prompts/${promptId}`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      variables,
      sessionId
    }),
  });

  if (!response.ok) {
    throw new Error(`HTTP ${response.status}: ${response.statusText}`);
  }

  return response.json();
}

// Usage in a component
import { useEffect, useState } from 'react';
import { resolvePrompt } from '../lib/prompts';

export function DynamicContent({ userId, contentType }: any) {
  const [content, setContent] = useState('');

  useEffect(() => {
    const fetchContent = async () => {
      try {
        const result = await resolvePrompt('dynamic-content', {
          contentType,
          userId
        }, userId);
        
        setContent(result.content);
      } catch (error) {
        console.error('Failed to load content:', error);
        setContent('Default content');
      }
    };

    fetchContent();
  }, [userId, contentType]);

  return <div dangerouslySetInnerHTML={{ __html: content }} />;
}

App Router (Next.js 13+)

// app/api/prompts/[id]/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { PromptCompose } from '@promptcompose/sdk';

const promptCompose = new PromptCompose(
  process.env.PROMPT_COMPOSE_API_KEY!,
  process.env.PROMPT_COMPOSE_PROJECT_ID!
);

export async function POST(
  request: NextRequest,
  { params }: { params: { id: string } }
) {
  try {
    await promptCompose.init();
    
    const body = await request.json();
    const { variables, sessionId } = body;

    const result = await promptCompose.resolvePrompt(params.id, {
      config: {
        abTesting: { sessionId }
      }
    }, variables);

    return NextResponse.json({
      content: result.content,
      variant: result.variant?.name,
      test: result.abTest?.name
    });
  } catch (error) {
    console.error('Prompt resolution failed:', error);
    return NextResponse.json(
      { error: 'Failed to resolve prompt' },
      { status: 500 }
    );
  }
}

Express.js Backend

Middleware

// middleware/promptCompose.ts
import { Request, Response, NextFunction } from 'express';
import { PromptCompose } from '@promptcompose/sdk';

interface PromptComposeRequest extends Request {
  promptCompose?: {
    resolve: (promptId: string, variables?: any) => Promise<any>;
    reportConversion: (testId: string, variantId: string, success: boolean) => Promise<void>;
  };
}

export function promptComposeMiddleware(
  promptCompose: PromptCompose
) {
  return async (req: PromptComposeRequest, res: Response, next: NextFunction) => {
    const userId = req.user?.id || req.sessionID;

    req.promptCompose = {
      resolve: async (promptId: string, variables?: any) => {
        return await promptCompose.resolvePrompt(promptId, {
          config: {
            abTesting: { sessionId: `user-${userId}` }
          }
        }, variables);
      },

      reportConversion: async (testId: string, variantId: string, success: boolean) => {
        return await promptCompose.reportABResult(testId, {
          variantId,
          status: success ? 'success' : 'fail',
          sessionId: `user-${userId}`
        });
      }
    };

    next();
  };
}

Server Setup

// server.ts
import express from 'express';
import { PromptCompose } from '@promptcompose/sdk';
import { promptComposeMiddleware } from './middleware/promptCompose';

const app = express();
app.use(express.json());

// Initialize PromptCompose SDK
const promptCompose = new PromptCompose(
  process.env.PROMPT_COMPOSE_API_KEY!,
  process.env.PROMPT_COMPOSE_PROJECT_ID!
);

// Initialize SDK on server startup
promptCompose.init().then(() => {
  console.log('PromptCompose SDK initialized');
}).catch(console.error);

// Apply middleware
app.use(promptComposeMiddleware(promptCompose));

// Email generation endpoint
app.post('/api/emails/welcome', async (req: any, res) => {
  try {
    const { userEmail, userName } = req.body;
    
    const result = await req.promptCompose.resolve('welcome-email', {
      userName,
      userEmail,
      companyName: 'Your Company'
    });

    // Send the email (using your email service)
    await sendEmail({
      to: userEmail,
      subject: 'Welcome!',
      html: result.content
    });

    res.json({ 
      success: true, 
      variant: result.variant?.name 
    });
  } catch (error) {
    console.error('Failed to send welcome email:', error);
    res.status(500).json({ error: 'Failed to send email' });
  }
});

// Conversion tracking endpoint
app.post('/api/conversions/:testId/:variantId', async (req: any, res) => {
  try {
    const { testId, variantId } = req.params;
    const { success } = req.body;

    await req.promptCompose.reportConversion(testId, variantId, success);

    res.json({ success: true });
  } catch (error) {
    console.error('Failed to report conversion:', error);
    res.status(500).json({ error: 'Failed to report conversion' });
  }
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

Advanced Use Cases

E-commerce Product Recommendations

// services/ProductRecommendationService.ts
import { PromptCompose } from '@promptcompose/sdk';

interface Product {
  id: string;
  name: string;
  price: number;
  category: string;
}

interface User {
  id: string;
  name: string;
  purchaseHistory: string[];
  preferences: string[];
}

class ProductRecommendationService {
  private promptCompose: PromptCompose;

  constructor(apiKey: string, projectId: string) {
    this.promptCompose = new PromptCompose(apiKey, projectId);
  }

  async getRecommendationMessage(
    user: User, 
    products: Product[]
  ): Promise<string> {
    const result = await this.promptCompose.resolvePrompt('product-recommendation', {
      config: {
        abTesting: { sessionId: `user-${user.id}` }
      }
    }, {
      userName: user.name,
      recentPurchases: user.purchaseHistory.slice(-3).join(', '),
      preferences: user.preferences.join(', '),
      recommendedProducts: products.map(p => `${p.name} ($${p.price})`).join(', '),
      productCount: products.length
    });

    return result.content;
  }

  async trackPurchaseConversion(
    user: User,
    testId: string,
    variantId: string,
    purchasedProductId: string
  ) {
    await this.promptCompose.reportABResult(testId, {
      variantId,
      status: 'success',
      sessionId: `user-${user.id}`
    });

    console.log(`Purchase conversion tracked for user ${user.id}`);
  }
}

// Usage
const recommendationService = new ProductRecommendationService(
  process.env.PROMPT_COMPOSE_API_KEY!,
  process.env.PROMPT_COMPOSE_PROJECT_ID!
);

const user = {
  id: '123',
  name: 'John Doe',
  purchaseHistory: ['laptop', 'mouse', 'keyboard'],
  preferences: ['electronics', 'productivity']
};

const products = [
  { id: '1', name: 'Monitor', price: 299, category: 'electronics' },
  { id: '2', name: 'Webcam', price: 89, category: 'electronics' }
];

const message = await recommendationService.getRecommendationMessage(user, products);

Customer Support Automation

// services/SupportService.ts
interface SupportTicket {
  id: string;
  userId: string;
  category: 'billing' | 'technical' | 'general';
  priority: 'low' | 'medium' | 'high' | 'urgent';
  description: string;
  userTier: 'free' | 'pro' | 'enterprise';
}

class SupportService {
  private promptCompose: PromptCompose;

  constructor(apiKey: string, projectId: string) {
    this.promptCompose = new PromptCompose(apiKey, projectId);
  }

  async generateResponse(ticket: SupportTicket): Promise<{
    response: string;
    shouldEscalate: boolean;
  }> {
    // Choose prompt based on category
    const promptId = this.getPromptForCategory(ticket.category);
    
    const result = await this.promptCompose.resolvePrompt(promptId, {
      config: {
        abTesting: { sessionId: `ticket-${ticket.id}` }
      }
    }, {
      ticketId: ticket.id,
      category: ticket.category,
      priority: ticket.priority,
      description: ticket.description,
      userTier: ticket.userTier,
      currentTime: new Date().toLocaleString()
    });

    // Determine if escalation is needed based on priority
    const shouldEscalate = ticket.priority === 'urgent' || 
                          ticket.userTier === 'enterprise';

    return {
      response: result.content,
      shouldEscalate
    };
  }

  async trackResolutionSuccess(
    ticketId: string,
    testId: string,
    variantId: string,
    resolved: boolean
  ) {
    await this.promptCompose.reportABResult(testId, {
      variantId,
      status: resolved ? 'success' : 'fail',
      sessionId: `ticket-${ticketId}`
    });
  }

  private getPromptForCategory(category: string): string {
    const prompts = {
      'billing': 'support-billing-response',
      'technical': 'support-technical-response',
      'general': 'support-general-response'
    };
    
    return prompts[category] || prompts['general'];
  }
}

Content Personalization

// services/ContentPersonalizationService.ts
interface UserProfile {
  id: string;
  interests: string[];
  readingLevel: 'beginner' | 'intermediate' | 'advanced';
  preferredTone: 'formal' | 'casual' | 'friendly';
  location: string;
  timezone: string;
}

class ContentPersonalizationService {
  private promptCompose: PromptCompose;

  constructor(apiKey: string, projectId: string) {
    this.promptCompose = new PromptCompose(apiKey, projectId);
  }

  async generatePersonalizedContent(
    contentType: string,
    topic: string,
    user: UserProfile
  ): Promise<string> {
    const promptId = `content-${contentType}`;
    
    const result = await this.promptCompose.resolvePrompt(promptId, {
      config: {
        abTesting: { sessionId: `user-${user.id}` }
      }
    }, {
      topic: topic,
      interests: user.interests.join(', '),
      readingLevel: user.readingLevel,
      tone: user.preferredTone,
      location: user.location,
      localTime: new Date().toLocaleString('en-US', { 
        timeZone: user.timezone 
      })
    });

    return result.content;
  }

  async trackEngagement(
    user: UserProfile,
    testId: string,
    variantId: string,
    engagementType: 'view' | 'click' | 'share' | 'complete'
  ) {
    const successTypes = ['click', 'share', 'complete'];
    const success = successTypes.includes(engagementType);

    await this.promptCompose.reportABResult(testId, {
      variantId,
      status: success ? 'success' : 'fail',
      sessionId: `user-${user.id}`
    });
  }
}

// Usage
const personalizationService = new ContentPersonalizationService(
  process.env.PROMPT_COMPOSE_API_KEY!,
  process.env.PROMPT_COMPOSE_PROJECT_ID!
);

const userProfile = {
  id: 'user123',
  interests: ['technology', 'productivity', 'business'],
  readingLevel: 'intermediate',
  preferredTone: 'casual',
  location: 'New York',
  timezone: 'America/New_York'
};

const blogContent = await personalizationService.generatePersonalizedContent(
  'blog-post',
  'artificial intelligence trends',
  userProfile
);

Testing and Development

Unit Testing with Jest

// __tests__/promptService.test.ts
import { PromptCompose } from '@promptcompose/sdk';
import { PromptService } from '../services/PromptService';

// Mock the SDK
jest.mock('@promptcompose/sdk');

describe('PromptService', () => {
  let promptService: PromptService;
  let mockPromptCompose: jest.Mocked<PromptCompose>;

  beforeEach(() => {
    mockPromptCompose = {
      init: jest.fn().mockResolvedValue({ message: 'Connected' }),
      resolvePrompt: jest.fn(),
      reportABResult: jest.fn()
    } as any;

    (PromptCompose as jest.MockedClass<typeof PromptCompose>)
      .mockImplementation(() => mockPromptCompose);

    promptService = new PromptService('test-key', 'test-project');
  });

  test('should resolve prompt successfully', async () => {
    const mockResult = {
      content: 'Hello, John!',
      variant: { name: 'friendly', publicId: 'var-123' },
      abTest: { name: 'greeting-test', publicId: 'test-123' }
    };

    mockPromptCompose.resolvePrompt.mockResolvedValue(mockResult);

    const result = await promptService.getGreeting('123', 'John');

    expect(result).toBe('Hello, John!');
    expect(mockPromptCompose.resolvePrompt).toHaveBeenCalledWith(
      'greeting-prompt',
      expect.objectContaining({
        config: expect.objectContaining({
          abTesting: expect.objectContaining({
            sessionId: 'user-123'
          })
        })
      }),
      { userName: 'John' }
    );
  });

  test('should handle API errors gracefully', async () => {
    mockPromptCompose.resolvePrompt.mockRejectedValue(
      new Error('API Error')
    );

    const result = await promptService.getGreeting('123', 'John');

    expect(result).toBe('Hello, John!'); // Fallback content
  });

  test('should report conversion successfully', async () => {
    mockPromptCompose.reportABResult.mockResolvedValue({});

    await promptService.reportConversion('test-123', 'var-123', '123', true);

    expect(mockPromptCompose.reportABResult).toHaveBeenCalledWith(
      'test-123',
      expect.objectContaining({
        variantId: 'var-123',
        status: 'success',
        sessionId: 'user-123'
      })
    );
  });
});

Mock Service for Development

// services/MockPromptService.ts (for development)
export class MockPromptService {
  private responses = new Map<string, string>();

  constructor() {
    // Setup mock responses
    this.responses.set('welcome-prompt', 'Welcome, {{userName}}! We\'re glad you\'re here.');
    this.responses.set('product-recommendation', 'Based on your interests in {{preferences}}, we recommend: {{recommendedProducts}}');
  }

  async resolvePrompt(promptId: string, config?: any, variables?: any) {
    const template = this.responses.get(promptId) || 'Default response';
    
    // Simple variable interpolation
    let content = template;
    if (variables) {
      Object.entries(variables).forEach(([key, value]) => {
        content = content.replace(new RegExp(`{{${key}}}`, 'g'), String(value));
      });
    }

    // Simulate A/B testing
    const variants = ['A', 'B'];
    const randomVariant = variants[Math.floor(Math.random() * variants.length)];

    return {
      content,
      variant: { name: `Variant ${randomVariant}`, publicId: `var-${randomVariant}` },
      abTest: { name: `${promptId}-test`, publicId: `test-${promptId}` }
    };
  }

  async reportABResult(testId: string, result: any) {
    console.log(`Mock: Reported conversion for test ${testId}:`, result);
    return result;
  }

  addMockResponse(promptId: string, content: string) {
    this.responses.set(promptId, content);
  }
}

Environment-Specific Service Factory

// services/PromptServiceFactory.ts
import { PromptCompose } from '@promptcompose/sdk';
import { MockPromptService } from './MockPromptService';

export class PromptServiceFactory {
  static create() {
    if (process.env.NODE_ENV === 'test') {
      return new MockPromptService();
    }

    if (process.env.NODE_ENV === 'development' && process.env.USE_MOCK_PROMPTS === 'true') {
      return new MockPromptService();
    }

    return new PromptCompose(
      process.env.PROMPT_COMPOSE_API_KEY!,
      process.env.PROMPT_COMPOSE_PROJECT_ID!,
      { debug: process.env.NODE_ENV !== 'production' }
    );
  }
}

// Usage
const promptService = PromptServiceFactory.create();

Performance Examples

Connection Pooling

// services/PromptConnectionPool.ts
class PromptConnectionPool {
  private pool: PromptCompose[] = [];
  private poolSize = 5;
  private currentIndex = 0;

  constructor(apiKey: string, projectId: string) {
    // Create connection pool
    for (let i = 0; i < this.poolSize; i++) {
      const instance = new PromptCompose(apiKey, projectId);
      instance.init(); // Initialize in background
      this.pool.push(instance);
    }
  }

  getInstance(): PromptCompose {
    const instance = this.pool[this.currentIndex];
    this.currentIndex = (this.currentIndex + 1) % this.poolSize;
    return instance;
  }

  async resolvePrompt(promptId: string, config?: any, variables?: any) {
    const instance = this.getInstance();
    return await instance.resolvePrompt(promptId, config, variables);
  }
}

Request Queuing

// services/QueuedPromptService.ts
interface QueuedRequest {
  promptId: string;
  config?: any;
  variables?: any;
  resolve: (result: any) => void;
  reject: (error: any) => void;
  priority: number;
}

class QueuedPromptService {
  private promptCompose: PromptCompose;
  private queue: QueuedRequest[] = [];
  private processing = false;
  private maxConcurrent = 3;
  private activeRequests = 0;

  constructor(apiKey: string, projectId: string) {
    this.promptCompose = new PromptCompose(apiKey, projectId);
    this.promptCompose.init();
  }

  async resolvePrompt(
    promptId: string, 
    config?: any, 
    variables?: any,
    priority = 0
  ): Promise<any> {
    return new Promise((resolve, reject) => {
      this.queue.push({
        promptId,
        config,
        variables,
        resolve,
        reject,
        priority
      });

      // Sort by priority (higher priority first)
      this.queue.sort((a, b) => b.priority - a.priority);

      this.processQueue();
    });
  }

  private async processQueue() {
    if (this.processing || this.activeRequests >= this.maxConcurrent) {
      return;
    }

    this.processing = true;

    while (this.queue.length > 0 && this.activeRequests < this.maxConcurrent) {
      const request = this.queue.shift()!;
      this.activeRequests++;

      this.processRequest(request);
    }

    this.processing = false;
  }

  private async processRequest(request: QueuedRequest) {
    try {
      const result = await this.promptCompose.resolvePrompt(
        request.promptId,
        request.config,
        request.variables
      );
      request.resolve(result);
    } catch (error) {
      request.reject(error);
    } finally {
      this.activeRequests--;
      this.processQueue(); // Continue processing queue
    }
  }
}

These examples demonstrate practical implementation patterns for various scenarios. Choose the patterns that best fit your application’s architecture and requirements.

For more advanced examples and patterns, see: