add-ai-model
Add a new AI image model to myimageupscaler.com, including model costs, provider configuration, model registry, quality tiers, scale capabilities, feature flags, tests, and free versus paid access rul
SKILL.md.agents/skills/add-ai-model/SKILL.md
GitHubAdd AI Model Skill
When adding a new AI model to the image upscaler, follow these steps in order. Each file must be updated for the model to work correctly.
Overview
- Provider: Replicate (primary), Gemini (alternative)
- Pricing: USD cost per API call + credit multiplier
- Tiers: Models can be restricted to subscription tiers (free, hobby, pro, business)
- Scale Support: Models must accurately report which scales they actually support
- Capabilities: Models must correctly declare 'upscale' vs enhancement-only capabilities
Important: Scale Support Accuracy
DO NOT claim scales that the model doesn't natively support:
- If the model has no scale parameter →
supportedScales: []and remove 'upscale' capability - If the model caps at 4x →
supportedScales: [2, 4](NOT [2, 4, 8]) - Only models with native 8x+ support should include 8 in
supportedScales
Common mistakes to avoid:
- ❌ Setting
supportedScales: [2, 4, 8]when the model only supports 2x and 4x - ❌ Including 'upscale' capability for enhancement-only models
- ❌ Using "two-pass hacks" to simulate unsupported scales
Edge Case: Free Tier Models (Direct Access Only)
Some models should be available to free users without creating a quality tier. Examples include p-image-edit and flux-kontext-fast.
For free tier models:
- DO NOT add a quality tier - Skip steps 4 (QualityTier, QUALITY_TIER_CONFIG, QUALITY_TIER_SCALES) and 5 (validation schema)
- Set
tierRestriction: nullin MODEL_CONFIG (not'hobby','pro', etc.) - Add to FREE_MODELS array in addition to HOBBY_MODELS, PRO_MODELS, BUSINESS_MODELS
// shared/config/model-costs.config.ts
FREE_MODELS: ['real-esrgan', 'gfpgan', 'nano-banana', 'p-image-edit', 'flux-kontext-fast'],
// In MODEL_CONFIG - note tierRestriction is null (not a string)
'flux-kontext-fast': {
cost: MODEL_COSTS.FLUX_KONTEXT_FAST_COST,
multiplier: 2, // Use lower multiplier for free tier (1-2x)
qualityScore: 9.1,
processingTime: MODEL_COSTS.PROCESSING_TIME_MEDIUM,
maxInputResolution: MODEL_COSTS.MAX_INPUT_RESOLUTION,
maxOutputResolution: MODEL_COSTS.MAX_OUTPUT_RESOLUTION,
supportedScales: [], // Enhancement-only
tierRestriction: null, // null = free tier, not 'hobby'/'pro'/'business'
},
- In model-registry.ts - use
tierRestriction: undefined(not a string):
{
id: 'flux-kontext-fast',
displayName: 'Flux Kontext',
// ...
isEnabled: true, // Always enabled for free tier
tierRestriction: undefined, // undefined = free tier
}
Free tier vs Paid tier models:
| Aspect | Free Tier | Paid Tier (hobby/pro/business) |
|---|---|---|
| Quality Tier | NO - direct model access only | YES - added to PREMIUM_QUALITY_TIERS |
| tierRestriction | null or undefined |
'hobby', 'pro', or 'business' |
| FREE_MODELS array | ✅ Included | ❌ Not included |
| isEnabled | true |
serverEnv.ENABLE_PREMIUM_MODELS |
| Credit multiplier | 1-2x | 3-8x |
Required Files (in order)
1. Cost Configuration
File: shared/config/model-costs.config.ts
Add the USD cost per API call:
export const MODEL_COSTS = {
// ... existing costs
NEW_MODEL_COST: 0.03, // USD per call
};
Add to tier arrays (HOBBY_MODELS, PRO_MODELS, BUSINESS_MODELS):
HOBBY_MODELS: [
// ... existing models
'new-model-id',
],
Add MODEL_CONFIG entry:
'new-model-id': {
cost: MODEL_COSTS.NEW_MODEL_COST,
multiplier: 3, // Credit multiplier
qualityScore: 9.2, // 1-10 quality rating
processingTime: MODEL_COSTS.PROCESSING_TIME_MEDIUM,
maxInputResolution: MODEL_COSTS.MAX_INPUT_RESOLUTION,
maxOutputResolution: MODEL_COSTS.MAX_OUTPUT_RESOLUTION,
// IMPORTANT: Only include scales the model ACTUALLY supports
// - If no scale param: [] (enhancement-only)
// - If 2x/4x only: [2, 4]
// - If native 8x: [2, 4, 8]
supportedScales: [2, 4], // Adjust based on actual model support
tierRestriction: 'hobby', // null for free, 'hobby'/'pro'/'business' for paid
},
If adding a new quality tier, add to PREMIUM_QUALITY_TIERS:
PREMIUM_QUALITY_TIERS: ['auto', 'new-tier', 'hd-upscale', ...] as const,
2. Credit Multiplier
File: shared/config/credits.config.ts
Add the credit multiplier constant:
export const CREDIT_COSTS = {
// ... existing multipliers
NEW_MODEL_MULTIPLIER: 3, // Credits = base_cost * multiplier
};
Add MODEL_CREDIT_COSTS entry:
'new-model-id': {
upscale: CREDIT_COSTS.BASE_UPSCALE_COST * CREDIT_COSTS.NEW_MODEL_MULTIPLIER,
enhance: CREDIT_COSTS.BASE_ENHANCE_COST * CREDIT_COSTS.NEW_MODEL_MULTIPLIER,
both: CREDIT_COSTS.BASE_BOTH_COST * CREDIT_COSTS.NEW_MODEL_MULTIPLIER,
custom: CREDIT_COSTS.BASE_CUSTOM_COST * CREDIT_COSTS.NEW_MODEL_MULTIPLIER,
},
3. Model Registry Types
File: server/services/model-registry.types.ts
Add to ModelId type:
export type ModelId =
| 'real-esrgan'
// ... existing models
| 'new-model-id';
4. Shared Types (Duplicate ModelId)
File: shared/types/coreflow.types.ts
Add to ModelId type (there's a duplicate here):
export type ModelId =
| 'real-esrgan'
// ... existing models
| 'new-model-id';
If adding a new quality tier, update QualityTier type:
export type QualityTier =
| 'auto'
| 'quick'
| 'face-restore'
| 'new-tier' // Add in credit order
| 'hd-upscale';
// ...
And add QUALITY_TIER_CONFIG entry:
'new-tier': {
label: 'New Tier Label',
credits: 3,
modelId: 'new-model-id',
description: 'Short description',
bestFor: 'Use case description',
smartAnalysisAlwaysOn: false,
},
IMPORTANT: Add QUALITY_TIER_SCALES entry (defines which scales the tier's model supports):
export const QUALITY_TIER_SCALES: Record<QualityTier, (2 | 4 | 8)[]> = {
// ... existing tiers
'new-tier': [2, 4], // Must match model's actual supportedScales
// ...
};
5. Validation Schema
File: shared/validation/upscale.schema.ts
If adding a new quality tier, update the Zod enum:
qualityTier: z
.enum(['auto', 'quick', 'face-restore', 'new-tier', 'hd-upscale', ...])
.default('auto'),
6. Model Registry
File: server/services/model-registry.ts
Add to DEFAULT_MODEL_VERSIONS:
const DEFAULT_MODEL_VERSIONS: Record<string, string> = {
// ... existing versions
'new-model-id': 'provider/model-name', // Replicate model identifier
};
Add to MODEL_COSTS map:
const MODEL_COSTS: Record<string, number> = {
// ... existing costs
'new-model-id': CONFIG_MODEL_COSTS.NEW_MODEL_COST,
};
Add to MODEL_CREDIT_MULTIPLIERS map:
const MODEL_CREDIT_MULTIPLIERS: Record<string, number> = {
// ... existing multipliers
'new-model-id': CREDIT_COSTS.NEW_MODEL_MULTIPLIER,
};
Add to getModelVersion overrides:
private getModelVersion(modelId: string): string {
const overrides: Record<string, string | undefined> = {
// ... existing overrides
'new-model-id': serverEnv.MODEL_VERSION_NEW_MODEL,
};
return overrides[modelId] || DEFAULT_MODEL_VERSIONS[modelId];
}
Add model config to loadModelsFromEnvironment():
{
id: 'new-model-id',
displayName: 'Display Name',
provider: 'replicate',
modelVersion: this.getModelVersion('new-model-id'),
// CRITICAL: Only include 'upscale' if the model actually changes dimensions
// - Enhancement-only models: remove 'upscale', keep 'enhance', 'denoise', etc.
capabilities: ['upscale', 'enhance', 'denoise'],
costPerRun: MODEL_COSTS['new-model-id'],
creditMultiplier: MODEL_CREDIT_MULTIPLIERS['new-model-id'],
qualityScore: 9.2,
processingTimeMs: TIMEOUTS.CLARITY_UPSCALER_PROCESSING_TIME,
maxInputResolution: CONFIG_MODEL_COSTS.MAX_INPUT_RESOLUTION,
maxOutputResolution: CONFIG_MODEL_COSTS.MAX_OUTPUT_RESOLUTION,
// IMPORTANT: Match this to the model's actual scale support
// - Enhancement-only: []
// - 2x/4x max: [2, 4]
// - Native 8x+: [2, 4, 8]
supportedScales: [2, 4], // Adjust based on actual model support
isEnabled: serverEnv.ENABLE_PREMIUM_MODELS,
tierRestriction: 'hobby',
},
7. Replicate Service
File: server/services/replicate.service.ts
Add input interface (check Replicate docs for exact params):
interface INewModelInput {
prompt: string;
image: string[];
// ... model-specific params
}
Update buildModelInput return type:
private buildModelInput(...):
| IFluxKontextInput
// ... existing types
| INewModelInput {
Add case in buildModelInput switch:
case 'new-model-id': {
let effectivePrompt = customPrompt;
if (!effectivePrompt) {
effectivePrompt = enhance
? `Upscale and enhance this image to ${scale}x resolution.`
: `Upscale this image to ${scale}x resolution.`;
// Add enhancement instructions...
}
return {
prompt: effectivePrompt,
image: [imageDataUrl],
// ... model-specific params
};
}
8. Environment Variables
File: shared/config/env.ts
Add to serverEnvSchema:
MODEL_VERSION_NEW_MODEL: z.string().optional(),
Add to loadServerEnv():
MODEL_VERSION_NEW_MODEL: process.env.MODEL_VERSION_NEW_MODEL,
Verification Checklist
After making all changes, run:
yarn verify
Then test:
- Select the new quality tier in UI
- Process an image
- Verify credits are deducted correctly
- Check Replicate dashboard for API call
Credit Economics Reference
| Cost Range | Suggested Multiplier | Example |
|---|---|---|
| $0.001-0.005 | 1x | real-esrgan |
| $0.005-0.01 | 2x | gfpgan |
| $0.01-0.05 | 3-4x | qwen-image-edit, clarity |
| $0.05-0.10 | 5-6x | flux-2-pro |
| $0.10+ | 7-8x | nano-banana-pro |