import type { ModelNodeDefinition } from '../types';

export const NODE_DEFINITIONS: Record<string, ModelNodeDefinition> = {
  'gpt-image-1-generate': {
    id: 'gpt-image-1-generate',
    displayName: 'GPT Image 1',
    category: 'image-gen',
    apiProvider: 'openai',
    apiEndpoint: '/v1/images/generations',
    envKeyName: 'OPENAI_API_KEY',
    executionPattern: 'sync',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'enum',
        required: true,
        default: 'gpt-image-1',
        options: [
          { label: 'GPT Image 1', value: 'gpt-image-1' },
          { label: 'GPT Image 1.5', value: 'gpt-image-1.5' },
          { label: 'GPT Image 1 Mini', value: 'gpt-image-1-mini' },
        ],
      },
      {
        key: 'size',
        label: 'Size',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: '1024×1024', value: '1024x1024' },
          { label: '1536×1024', value: '1536x1024' },
          { label: '1024×1536', value: '1024x1536' },
        ],
      },
      {
        key: 'quality',
        label: 'Quality',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: 'Low', value: 'low' },
          { label: 'Medium', value: 'medium' },
          { label: 'High', value: 'high' },
        ],
      },
      {
        key: 'output_format',
        label: 'Format',
        type: 'enum',
        required: false,
        default: 'png',
        options: [
          { label: 'PNG', value: 'png' },
          { label: 'JPEG', value: 'jpeg' },
          { label: 'WebP', value: 'webp' },
        ],
      },
      {
        key: 'background',
        label: 'Background',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: 'Transparent', value: 'transparent' },
          { label: 'Opaque', value: 'opaque' },
        ],
      },
    ],
  },

  'claude-chat': {
    id: 'claude-chat',
    displayName: 'Claude',
    category: 'text-gen',
    apiProvider: 'anthropic',
    apiEndpoint: '/v1/messages',
    envKeyName: 'ANTHROPIC_API_KEY',
    executionPattern: 'stream',
    inputPorts: [
      { id: 'messages', label: 'Messages', dataType: 'Text', required: true },
      { id: 'images', label: 'Images', dataType: 'Image', required: false, multiple: true },
    ],
    outputPorts: [
      { id: 'text', label: 'Text', dataType: 'Text', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'enum',
        required: true,
        default: 'claude-sonnet-4-6',
        options: [
          { label: 'Claude Fable 5 (flagship)', value: 'claude-fable-5' },
          { label: 'Claude Opus 4.8', value: 'claude-opus-4-8' },
          { label: 'Claude Sonnet 4.6', value: 'claude-sonnet-4-6' },
          { label: 'Claude Haiku 4.5', value: 'claude-haiku-4-5-20251001' },
          { label: 'Claude Opus 4.7 (legacy)', value: 'claude-opus-4-7' },
          { label: 'Claude Opus 4.6 (legacy)', value: 'claude-opus-4-6' },
        ],
      },
      {
        key: 'max_tokens',
        label: 'Max Tokens',
        type: 'integer',
        required: true,
        default: 4096,
        min: 1,
        max: 200000,
      },
      {
        key: 'temperature',
        label: 'Temperature',
        type: 'float',
        required: false,
        default: 1,
        min: 0,
        max: 1,
        step: 0.1,
      },
      {
        key: 'system',
        label: 'System Prompt',
        type: 'textarea',
        required: false,
        default: '',
        placeholder: 'System instructions...',
      },
      {
        key: 'top_p',
        label: 'Top P',
        type: 'float',
        required: false,
        min: 0,
        max: 1,
        step: 0.05,
        placeholder: 'Default',
      },
      {
        key: 'stop_sequences',
        label: 'Stop Sequences',
        type: 'string',
        required: false,
        placeholder: 'Comma-separated',
      },
      {
        key: 'extended_thinking',
        label: 'Extended Thinking',
        type: 'boolean',
        required: false,
        default: false,
        // Fable/Mythos 5 use always-on adaptive thinking — no extended-thinking param.
        visibleWhen: { model: ['claude-opus-4-8', 'claude-sonnet-4-6', 'claude-haiku-4-5-20251001', 'claude-opus-4-7', 'claude-opus-4-6'] },
      },
      {
        key: 'thinkingBudget',
        label: 'Thinking Budget',
        type: 'integer',
        required: false,
        default: 10000,
        placeholder: 'Default (min 1024)',
        min: 1024,
        max: 200000,
        condition: 'extended_thinking',
        visibleWhen: { model: ['claude-opus-4-8', 'claude-sonnet-4-6', 'claude-haiku-4-5-20251001', 'claude-opus-4-7', 'claude-opus-4-6'] },
      },
      {
        key: 'prompt_caching',
        label: 'Prompt Caching',
        type: 'boolean',
        required: false,
        default: false,
      },
    ],
  },

  'runway-video': {
    id: 'runway-video',
    displayName: 'Runway Video',
    category: 'video-gen',
    apiProvider: 'runway',
    apiEndpoint: '/v1/image_to_video',
    envKeyName: 'RUNWAY_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: false },
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'enum',
        required: true,
        default: 'gen4.5',
        options: [
          { label: 'Gen-4.5', value: 'gen4.5' },
          { label: 'Seedance 2.0', value: 'seedance2' },
          { label: 'Seedance 2.0 Fast', value: 'seedance2_fast' },
          { label: 'HappyHorse 1.0', value: 'happyhorse_1_0' },
          { label: 'Gen-4 Turbo', value: 'gen4_turbo' },
          { label: 'Gen-3a Turbo (legacy)', value: 'gen3a_turbo' },
          { label: 'Veo 3.1', value: 'veo3.1' },
          { label: 'Veo 3.1 Fast', value: 'veo3.1_fast' },
          { label: 'Veo 3', value: 'veo3' },
        ],
      },
      {
        key: 'duration',
        label: 'Duration',
        type: 'integer',
        required: false,
        default: 5,
        min: 2,
        max: 10,
      },
      {
        key: 'ratio',
        label: 'Ratio',
        type: 'enum',
        required: false,
        default: '1280:720',
        options: [
          { label: '1280x720 (16:9)', value: '1280:720' },
          { label: '720x1280 (9:16)', value: '720:1280' },
          { label: '1104x832 (4:3)', value: '1104:832' },
          { label: '832x1104 (3:4)', value: '832:1104' },
          { label: '960x960 (1:1)', value: '960:960' },
          { label: '1584x672 (21:9)', value: '1584:672' },
        ],
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
        min: 0,
        max: 4294967295,
      },
    ],
  },

  'runway-aleph': {
    id: 'runway-aleph',
    displayName: 'Runway Aleph',
    category: 'video-gen',
    apiProvider: 'runway',
    apiEndpoint: '/v1/video_to_video',
    envKeyName: 'RUNWAY_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: true },
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'reference', label: 'Reference Image', dataType: 'Image', required: false },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'enum',
        required: false,
        default: 'gen4_aleph',
        options: [
          { label: 'Aleph 2.0', value: 'aleph2' },
          { label: 'Gen-4 Aleph', value: 'gen4_aleph' },
        ],
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
        min: 0,
        max: 4294967295,
      },
    ],
  },

  'runway-image': {
    id: 'runway-image',
    displayName: 'Runway Image',
    category: 'image-gen',
    apiProvider: 'runway',
    apiEndpoint: '/v1/text_to_image',
    envKeyName: 'RUNWAY_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'images', label: 'Reference Images', dataType: 'Image', required: false, multiple: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'enum',
        required: true,
        default: 'gen4_image',
        options: [
          { label: 'Gen-4 Image', value: 'gen4_image' },
          { label: 'Gen-4 Image Turbo', value: 'gen4_image_turbo' },
          { label: 'Nano Banana Pro (Gemini 3)', value: 'gemini_image3_pro' },
          { label: 'GPT Image 2', value: 'gpt_image_2' },
          { label: 'Gemini 2.5 Flash', value: 'gemini_2.5_flash' },
        ],
      },
      {
        key: 'ratio',
        label: 'Ratio',
        type: 'enum',
        required: false,
        default: '1360:768',
        options: [
          { label: '1360x768 (16:9)', value: '1360:768' },
          { label: '720x1280 (9:16)', value: '720:1280' },
          { label: '1024x1024 (1:1)', value: '1024:1024' },
          { label: '1080x1080', value: '1080:1080' },
          { label: '1168x880', value: '1168:880' },
          { label: '1440x1080', value: '1440:1080' },
          { label: '1080x1440', value: '1080:1440' },
          { label: '1920x1080', value: '1920:1080' },
          { label: '1080x1920', value: '1080:1920' },
          { label: '1808x768', value: '1808:768' },
          { label: '2112x912', value: '2112:912' },
        ],
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
        min: 0,
        max: 4294967295,
      },
    ],
  },

  'runway-upscale': {
    id: 'runway-upscale',
    displayName: 'Runway Upscale',
    category: 'transform',
    apiProvider: 'runway',
    apiEndpoint: '/v1/image_upscale',
    envKeyName: 'RUNWAY_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'scaleFactor',
        label: 'Scale Factor',
        type: 'enum',
        required: false,
        default: 2,
        options: [
          { label: '2x', value: 2 },
          { label: '4x', value: 4 },
          { label: '8x', value: 8 },
          { label: '16x', value: 16 },
        ],
      },
      {
        key: 'flavor',
        label: 'Flavor',
        type: 'enum',
        required: false,
        default: 'photo',
        options: [
          { label: 'Photo', value: 'photo' },
          { label: 'Photo Denoiser', value: 'photo_denoiser' },
          { label: 'Sublime (illustration)', value: 'sublime' },
        ],
      },
      {
        key: 'sharpen',
        label: 'Sharpen',
        type: 'integer',
        required: false,
        min: 0,
        max: 100,
        placeholder: '0-100 (default none)',
      },
      {
        key: 'smartGrain',
        label: 'Smart Grain',
        type: 'integer',
        required: false,
        min: 0,
        max: 100,
        placeholder: '0-100 (default none)',
      },
      {
        key: 'ultraDetail',
        label: 'Ultra Detail',
        type: 'integer',
        required: false,
        min: 0,
        max: 100,
        placeholder: '0-100 (default none)',
      },
    ],
  },

  'runway-act-two': {
    id: 'runway-act-two',
    displayName: 'Runway Act-Two',
    category: 'video-gen',
    apiProvider: 'runway',
    apiEndpoint: '/v1/character_performance',
    envKeyName: 'RUNWAY_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'character_image', label: 'Character Image', dataType: 'Image', required: false },
      { id: 'character_video', label: 'Character Video', dataType: 'Video', required: false },
      { id: 'reference', label: 'Performance Video', dataType: 'Video', required: true },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'bodyControl',
        label: 'Body Control',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'expressionIntensity',
        label: 'Expression Intensity',
        type: 'integer',
        required: false,
        default: 3,
        min: 1,
        max: 5,
      },
      {
        key: 'ratio',
        label: 'Ratio',
        type: 'enum',
        required: false,
        default: '1280:720',
        options: [
          { label: '1280x720 (16:9)', value: '1280:720' },
          { label: '720x1280 (9:16)', value: '720:1280' },
          { label: '960x960 (1:1)', value: '960:960' },
          { label: '1104x832 (4:3)', value: '1104:832' },
          { label: '832x1104 (3:4)', value: '832:1104' },
          { label: '1584x672 (21:9)', value: '1584:672' },
        ],
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
        min: 0,
        max: 4294967295,
      },
    ],
  },

  'runway-tts': {
    id: 'runway-tts',
    displayName: 'Runway TTS',
    category: 'audio-gen',
    apiProvider: 'runway',
    apiEndpoint: '/v1/text_to_speech',
    envKeyName: 'RUNWAY_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'text', label: 'Text', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'audio', label: 'Audio', dataType: 'Audio', required: false },
    ],
    params: [
      {
        key: 'voiceId',
        label: 'Voice',
        type: 'enum',
        required: false,
        default: 'Maya',
        options: [
          { label: 'Maya', value: 'Maya' },
          { label: 'Arjun', value: 'Arjun' },
          { label: 'Serene', value: 'Serene' },
          { label: 'Bernard', value: 'Bernard' },
          { label: 'Billy', value: 'Billy' },
          { label: 'Mark', value: 'Mark' },
          { label: 'Clint', value: 'Clint' },
          { label: 'Mabel', value: 'Mabel' },
          { label: 'Chad', value: 'Chad' },
          { label: 'Leslie', value: 'Leslie' },
          { label: 'Eleanor', value: 'Eleanor' },
          { label: 'Elias', value: 'Elias' },
          { label: 'Elliot', value: 'Elliot' },
          { label: 'Brodie', value: 'Brodie' },
          { label: 'Sandra', value: 'Sandra' },
          { label: 'Kirk', value: 'Kirk' },
          { label: 'Kylie', value: 'Kylie' },
          { label: 'Lara', value: 'Lara' },
          { label: 'Lisa', value: 'Lisa' },
          { label: 'Maggie', value: 'Maggie' },
          { label: 'Jack', value: 'Jack' },
          { label: 'Katie', value: 'Katie' },
          { label: 'Noah', value: 'Noah' },
          { label: 'James', value: 'James' },
          { label: 'Rina', value: 'Rina' },
          { label: 'Ella', value: 'Ella' },
          { label: 'Frank', value: 'Frank' },
          { label: 'Rachel', value: 'Rachel' },
          { label: 'Tom', value: 'Tom' },
          { label: 'Benjamin', value: 'Benjamin' },
        ],
      },
    ],
  },

  'runway-sts': {
    id: 'runway-sts',
    displayName: 'Runway Speech-to-Speech',
    category: 'audio-gen',
    apiProvider: 'runway',
    apiEndpoint: '/v1/speech_to_speech',
    envKeyName: 'RUNWAY_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'audio', label: 'Audio', dataType: 'Audio', required: false },
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    outputPorts: [
      { id: 'audio', label: 'Audio', dataType: 'Audio', required: false },
    ],
    params: [
      {
        key: 'voiceId',
        label: 'Voice',
        type: 'enum',
        required: false,
        default: 'Maya',
        options: [
          { label: 'Maya', value: 'Maya' },
          { label: 'Arjun', value: 'Arjun' },
          { label: 'Serene', value: 'Serene' },
          { label: 'Bernard', value: 'Bernard' },
          { label: 'Billy', value: 'Billy' },
          { label: 'Mark', value: 'Mark' },
          { label: 'Clint', value: 'Clint' },
          { label: 'Mabel', value: 'Mabel' },
          { label: 'Chad', value: 'Chad' },
          { label: 'Leslie', value: 'Leslie' },
          { label: 'Eleanor', value: 'Eleanor' },
          { label: 'Maggie', value: 'Maggie' },
          { label: 'Jack', value: 'Jack' },
          { label: 'Noah', value: 'Noah' },
          { label: 'James', value: 'James' },
          { label: 'Ella', value: 'Ella' },
          { label: 'Frank', value: 'Frank' },
          { label: 'Rachel', value: 'Rachel' },
          { label: 'Tom', value: 'Tom' },
        ],
      },
      {
        key: 'removeBackgroundNoise',
        label: 'Remove Background Noise',
        type: 'boolean',
        required: false,
        default: false,
      },
    ],
  },

  'runway-dubbing': {
    id: 'runway-dubbing',
    displayName: 'Runway Voice Dubbing',
    category: 'audio-gen',
    apiProvider: 'runway',
    apiEndpoint: '/v1/voice_dubbing',
    envKeyName: 'RUNWAY_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'audio', label: 'Audio', dataType: 'Audio', required: true },
    ],
    outputPorts: [
      { id: 'audio', label: 'Audio', dataType: 'Audio', required: false },
    ],
    params: [
      {
        key: 'targetLang',
        label: 'Target Language',
        type: 'enum',
        required: true,
        default: 'es',
        options: [
          { label: 'English', value: 'en' },
          { label: 'Spanish', value: 'es' },
          { label: 'French', value: 'fr' },
          { label: 'German', value: 'de' },
          { label: 'Italian', value: 'it' },
          { label: 'Portuguese', value: 'pt' },
          { label: 'Japanese', value: 'ja' },
          { label: 'Korean', value: 'ko' },
          { label: 'Chinese', value: 'zh' },
          { label: 'Arabic', value: 'ar' },
          { label: 'Russian', value: 'ru' },
          { label: 'Hindi', value: 'hi' },
          { label: 'Dutch', value: 'nl' },
          { label: 'Turkish', value: 'tr' },
          { label: 'Polish', value: 'pl' },
          { label: 'Swedish', value: 'sv' },
          { label: 'Filipino', value: 'fil' },
          { label: 'Indonesian', value: 'id' },
          { label: 'Romanian', value: 'ro' },
          { label: 'Ukrainian', value: 'uk' },
          { label: 'Greek', value: 'el' },
          { label: 'Czech', value: 'cs' },
          { label: 'Danish', value: 'da' },
          { label: 'Finnish', value: 'fi' },
          { label: 'Bulgarian', value: 'bg' },
          { label: 'Croatian', value: 'hr' },
          { label: 'Slovak', value: 'sk' },
          { label: 'Tamil', value: 'ta' },
        ],
      },
      {
        key: 'disableVoiceCloning',
        label: 'Disable Voice Cloning',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'dropBackgroundAudio',
        label: 'Drop Background Audio',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'numSpeakers',
        label: 'Number of Speakers',
        type: 'integer',
        required: false,
        placeholder: 'Auto-detect',
        min: 1,
        max: 10,
      },
    ],
  },

  'elevenlabs-tts': {
    id: 'elevenlabs-tts',
    displayName: 'ElevenLabs TTS',
    category: 'audio-gen',
    apiProvider: 'elevenlabs',
    apiEndpoint: '/v1/text-to-speech/{voice_id}',
    envKeyName: 'ELEVENLABS_API_KEY',
    executionPattern: 'sync',
    inputPorts: [
      { id: 'text', label: 'Text', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'audio', label: 'Audio', dataType: 'Audio', required: false },
    ],
    params: [
      {
        key: 'model_id',
        label: 'Model',
        type: 'enum',
        required: false,
        default: 'eleven_multilingual_v2',
        options: [
          { label: 'v3 (Highest Quality)', value: 'eleven_v3' },
          { label: 'Multilingual v2', value: 'eleven_multilingual_v2' },
          { label: 'Turbo v2.5 (Low Latency)', value: 'eleven_turbo_v2_5' },
          { label: 'Flash v2.5 (Fastest)', value: 'eleven_flash_v2_5' },
          { label: 'Turbo v2', value: 'eleven_turbo_v2' },
          { label: 'Flash v2', value: 'eleven_flash_v2' },
        ],
      },
      {
        key: 'stability',
        label: 'Stability',
        type: 'float',
        required: false,
        default: 0.5,
        min: 0,
        max: 1,
        step: 0.05,
      },
      {
        key: 'voice_id',
        label: 'Voice ID',
        type: 'string',
        required: false,
        default: '21m00Tcm4TlvDq8ikWAM',
        placeholder: 'Rachel (default)',
      },
      {
        key: 'similarity_boost',
        label: 'Similarity Boost',
        type: 'float',
        required: false,
        default: 0.75,
        min: 0,
        max: 1,
        step: 0.05,
      },
      {
        key: 'style',
        label: 'Style',
        type: 'float',
        required: false,
        default: 0,
        min: 0,
        max: 1,
        step: 0.05,
      },
      {
        key: 'use_speaker_boost',
        label: 'Speaker Boost',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'speed',
        label: 'Speed',
        type: 'float',
        required: false,
        default: 1.0,
        min: 0.7,
        max: 1.2,
        step: 0.05,
      },
      {
        key: 'output_format',
        label: 'Output Format',
        type: 'enum',
        required: false,
        default: 'mp3_44100_128',
        options: [
          { label: 'MP3 44.1kHz', value: 'mp3_44100_128' },
          { label: 'MP3 22kHz', value: 'mp3_22050_32' },
          { label: 'PCM 16kHz', value: 'pcm_16000' },
          { label: 'PCM 24kHz', value: 'pcm_24000' },
          { label: 'PCM 44.1kHz', value: 'pcm_44100' },
        ],
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
  },

  'openai-stt': {
    id: 'openai-stt',
    displayName: 'OpenAI Whisper STT',
    category: 'audio-gen',
    apiProvider: 'openai',
    apiEndpoint: '/v1/audio/transcriptions',
    envKeyName: 'OPENAI_API_KEY',
    executionPattern: 'sync',
    inputPorts: [
      { id: 'audio', label: 'Audio', dataType: 'Audio', required: true },
    ],
    outputPorts: [
      { id: 'text', label: 'Text', dataType: 'Text', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'enum',
        required: false,
        default: 'whisper-1',
        options: [
          { label: 'Whisper 1', value: 'whisper-1' },
          { label: 'GPT-4o Transcribe', value: 'gpt-4o-transcribe' },
          { label: 'GPT-4o Mini Transcribe', value: 'gpt-4o-mini-transcribe' },
        ],
      },
      {
        key: 'language',
        label: 'Language',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto-detect', value: 'auto' },
          { label: 'English', value: 'en' },
          { label: 'Spanish', value: 'es' },
          { label: 'French', value: 'fr' },
          { label: 'German', value: 'de' },
          { label: 'Italian', value: 'it' },
          { label: 'Portuguese', value: 'pt' },
          { label: 'Japanese', value: 'ja' },
          { label: 'Korean', value: 'ko' },
          { label: 'Chinese', value: 'zh' },
          { label: 'Arabic', value: 'ar' },
          { label: 'Russian', value: 'ru' },
          { label: 'Hindi', value: 'hi' },
        ],
      },
      {
        key: 'response_format',
        label: 'Output Format',
        type: 'enum',
        required: false,
        default: 'text',
        options: [
          { label: 'Text', value: 'text' },
          { label: 'JSON', value: 'json' },
          { label: 'Verbose JSON', value: 'verbose_json' },
          { label: 'SRT Subtitles', value: 'srt' },
          { label: 'VTT Subtitles', value: 'vtt' },
        ],
      },
      {
        key: 'temperature',
        label: 'Temperature',
        type: 'float',
        required: false,
        default: 0,
        min: 0,
        max: 1,
        step: 0.1,
      },
      {
        key: 'prompt',
        label: 'Prompt',
        type: 'string',
        required: false,
        placeholder: 'Guide the model (optional)',
      },
    ],
  },

  'openai-translate': {
    id: 'openai-translate',
    displayName: 'OpenAI Audio Translate',
    category: 'audio-gen',
    apiProvider: 'openai',
    apiEndpoint: '/v1/audio/translations',
    envKeyName: 'OPENAI_API_KEY',
    executionPattern: 'sync',
    inputPorts: [
      { id: 'audio', label: 'Audio', dataType: 'Audio', required: true },
    ],
    outputPorts: [
      { id: 'text', label: 'English Text', dataType: 'Text', required: false },
    ],
    params: [
      {
        key: 'response_format',
        label: 'Output Format',
        type: 'enum',
        required: false,
        default: 'text',
        options: [
          { label: 'Text', value: 'text' },
          { label: 'JSON', value: 'json' },
          { label: 'Verbose JSON', value: 'verbose_json' },
          { label: 'SRT Subtitles', value: 'srt' },
          { label: 'VTT Subtitles', value: 'vtt' },
        ],
      },
      {
        key: 'temperature',
        label: 'Temperature',
        type: 'float',
        required: false,
        default: 0,
        min: 0,
        max: 1,
        step: 0.1,
      },
      {
        key: 'prompt',
        label: 'Prompt',
        type: 'string',
        required: false,
        placeholder: 'Guide the model (must be in English)',
      },
    ],
  },

  'openai-tts': {
    id: 'openai-tts',
    displayName: 'OpenAI TTS',
    category: 'audio-gen',
    apiProvider: 'openai',
    apiEndpoint: '/v1/audio/speech',
    envKeyName: 'OPENAI_API_KEY',
    executionPattern: 'sync',
    inputPorts: [
      { id: 'text', label: 'Text', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'audio', label: 'Audio', dataType: 'Audio', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'enum',
        required: false,
        default: 'tts-1',
        options: [
          { label: 'TTS-1', value: 'tts-1' },
          { label: 'TTS-1 HD', value: 'tts-1-hd' },
          { label: 'GPT-4o Mini TTS', value: 'gpt-4o-mini-tts' },
        ],
      },
      {
        key: 'voice',
        label: 'Voice',
        type: 'enum',
        required: false,
        default: 'alloy',
        options: [
          { label: 'Alloy', value: 'alloy' },
          { label: 'Ash', value: 'ash' },
          { label: 'Ballad', value: 'ballad' },
          { label: 'Cedar', value: 'cedar' },
          { label: 'Coral', value: 'coral' },
          { label: 'Echo', value: 'echo' },
          { label: 'Fable', value: 'fable' },
          { label: 'Marin', value: 'marin' },
          { label: 'Nova', value: 'nova' },
          { label: 'Onyx', value: 'onyx' },
          { label: 'Sage', value: 'sage' },
          { label: 'Shimmer', value: 'shimmer' },
          { label: 'Verse', value: 'verse' },
        ],
      },
      {
        key: 'speed',
        label: 'Speed',
        type: 'float',
        required: false,
        default: 1.0,
        min: 0.25,
        max: 4.0,
        step: 0.25,
      },
      {
        key: 'response_format',
        label: 'Format',
        type: 'enum',
        required: false,
        default: 'mp3',
        options: [
          { label: 'MP3', value: 'mp3' },
          { label: 'WAV', value: 'wav' },
          { label: 'FLAC', value: 'flac' },
          { label: 'Opus', value: 'opus' },
          { label: 'AAC', value: 'aac' },
          { label: 'PCM', value: 'pcm' },
        ],
      },
      {
        key: 'instructions',
        label: 'Voice Instructions',
        type: 'string',
        required: false,
        placeholder: 'e.g. "Speak slowly with warmth" (gpt-4o-mini-tts only)',
      },
    ],
  },

  'elevenlabs-sfx': {
    id: 'elevenlabs-sfx',
    displayName: 'ElevenLabs Sound Effects',
    category: 'audio-gen',
    apiProvider: 'elevenlabs',
    apiEndpoint: '/v1/sound-generation',
    envKeyName: 'ELEVENLABS_API_KEY',
    executionPattern: 'sync',
    inputPorts: [
      { id: 'text', label: 'Text', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'audio', label: 'Audio', dataType: 'Audio', required: false },
    ],
    params: [
      {
        key: 'duration_seconds',
        label: 'Duration (sec)',
        type: 'float',
        required: false,
        placeholder: 'Auto',
        min: 0.5,
        max: 30,
        step: 0.5,
      },
      {
        key: 'prompt_influence',
        label: 'Prompt Influence',
        type: 'float',
        required: false,
        default: 0.3,
        min: 0,
        max: 1,
        step: 0.05,
      },
      {
        key: 'loop',
        label: 'Seamless Loop',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'output_format',
        label: 'Output Format',
        type: 'enum',
        required: false,
        default: 'mp3_44100_128',
        options: [
          { label: 'MP3 44.1kHz', value: 'mp3_44100_128' },
          { label: 'MP3 22kHz', value: 'mp3_22050_32' },
          { label: 'PCM 44.1kHz', value: 'pcm_44100' },
          { label: 'PCM 24kHz', value: 'pcm_24000' },
        ],
      },
    ],
  },

  'elevenlabs-sts': {
    id: 'elevenlabs-sts',
    displayName: 'ElevenLabs Speech-to-Speech',
    category: 'audio-gen',
    apiProvider: 'elevenlabs',
    apiEndpoint: '/v1/speech-to-speech/{voice_id}',
    envKeyName: 'ELEVENLABS_API_KEY',
    executionPattern: 'sync',
    inputPorts: [
      { id: 'audio', label: 'Audio', dataType: 'Audio', required: true },
    ],
    outputPorts: [
      { id: 'audio', label: 'Audio', dataType: 'Audio', required: false },
    ],
    params: [
      {
        key: 'voice_id',
        label: 'Voice ID',
        type: 'string',
        required: false,
        default: '21m00Tcm4TlvDq8ikWAM',
        placeholder: 'Rachel (default)',
      },
      {
        key: 'model_id',
        label: 'Model',
        type: 'enum',
        required: false,
        default: 'eleven_english_sts_v2',
        options: [
          { label: 'English STS v2', value: 'eleven_english_sts_v2' },
          { label: 'Multilingual STS v2', value: 'eleven_multilingual_sts_v2' },
        ],
      },
      {
        key: 'stability',
        label: 'Stability',
        type: 'float',
        required: false,
        default: 0.5,
        min: 0,
        max: 1,
        step: 0.05,
      },
      {
        key: 'similarity_boost',
        label: 'Similarity Boost',
        type: 'float',
        required: false,
        default: 0.75,
        min: 0,
        max: 1,
        step: 0.05,
      },
      {
        key: 'remove_background_noise',
        label: 'Remove Background Noise',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
      {
        key: 'output_format',
        label: 'Output Format',
        type: 'enum',
        required: false,
        default: 'mp3_44100_128',
        options: [
          { label: 'MP3 44.1kHz', value: 'mp3_44100_128' },
          { label: 'MP3 22kHz', value: 'mp3_22050_32' },
          { label: 'PCM 44.1kHz', value: 'pcm_44100' },
          { label: 'PCM 24kHz', value: 'pcm_24000' },
        ],
      },
    ],
  },

  'elevenlabs-isolation': {
    id: 'elevenlabs-isolation',
    displayName: 'ElevenLabs Audio Isolation',
    category: 'audio-gen',
    apiProvider: 'elevenlabs',
    apiEndpoint: '/v1/audio-isolation',
    envKeyName: 'ELEVENLABS_API_KEY',
    executionPattern: 'sync',
    inputPorts: [
      { id: 'audio', label: 'Audio', dataType: 'Audio', required: true },
    ],
    outputPorts: [
      { id: 'audio', label: 'Isolated Audio', dataType: 'Audio', required: false },
    ],
    params: [],
  },

  'elevenlabs-dubbing': {
    id: 'elevenlabs-dubbing',
    displayName: 'ElevenLabs Dubbing',
    category: 'audio-gen',
    apiProvider: 'elevenlabs',
    apiEndpoint: '/v1/dubbing',
    envKeyName: 'ELEVENLABS_API_KEY',
    executionPattern: 'sync',
    inputPorts: [
      { id: 'audio', label: 'Audio', dataType: 'Audio', required: true },
    ],
    outputPorts: [
      { id: 'audio', label: 'Dubbed Audio', dataType: 'Audio', required: false },
    ],
    params: [
      {
        key: 'target_lang',
        label: 'Target Language',
        type: 'enum',
        required: true,
        default: 'es',
        options: [
          { label: 'English', value: 'en' },
          { label: 'Spanish', value: 'es' },
          { label: 'French', value: 'fr' },
          { label: 'German', value: 'de' },
          { label: 'Italian', value: 'it' },
          { label: 'Portuguese', value: 'pt' },
          { label: 'Japanese', value: 'ja' },
          { label: 'Korean', value: 'ko' },
          { label: 'Chinese', value: 'zh' },
          { label: 'Arabic', value: 'ar' },
          { label: 'Russian', value: 'ru' },
          { label: 'Hindi', value: 'hi' },
          { label: 'Dutch', value: 'nl' },
          { label: 'Turkish', value: 'tr' },
          { label: 'Polish', value: 'pl' },
          { label: 'Swedish', value: 'sv' },
        ],
      },
      {
        key: 'source_lang',
        label: 'Source Language',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto-detect', value: 'auto' },
          { label: 'English', value: 'en' },
          { label: 'Spanish', value: 'es' },
          { label: 'French', value: 'fr' },
          { label: 'German', value: 'de' },
          { label: 'Japanese', value: 'ja' },
          { label: 'Chinese', value: 'zh' },
        ],
      },
      {
        key: 'num_speakers',
        label: 'Number of Speakers',
        type: 'integer',
        required: false,
        placeholder: 'Auto-detect',
        min: 0,
        max: 10,
      },
      {
        key: 'drop_background_audio',
        label: 'Drop Background Audio',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'disable_voice_cloning',
        label: 'Disable Voice Cloning',
        type: 'boolean',
        required: false,
        default: false,
      },
    ],
  },

  'elevenlabs-stt': {
    id: 'elevenlabs-stt',
    displayName: 'ElevenLabs STT',
    category: 'audio-gen',
    apiProvider: 'elevenlabs',
    apiEndpoint: '/v1/speech-to-text',
    envKeyName: 'ELEVENLABS_API_KEY',
    executionPattern: 'sync',
    inputPorts: [
      { id: 'audio', label: 'Audio', dataType: 'Audio', required: true },
    ],
    outputPorts: [
      { id: 'text', label: 'Text', dataType: 'Text', required: false },
    ],
    params: [
      {
        key: 'model_id',
        label: 'Model',
        type: 'enum',
        required: false,
        default: 'scribe_v1',
        options: [
          { label: 'Scribe v1', value: 'scribe_v1' },
          { label: 'Scribe v2', value: 'scribe_v2' },
        ],
      },
      {
        key: 'language_code',
        label: 'Language',
        type: 'string',
        required: false,
        placeholder: 'Auto-detect (ISO code, e.g. en)',
      },
      {
        key: 'diarize',
        label: 'Diarize (label speakers)',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'num_speakers',
        label: 'Max Speakers',
        type: 'integer',
        required: false,
        placeholder: 'Auto',
        min: 1,
        max: 32,
      },
      {
        key: 'tag_audio_events',
        label: 'Tag Audio Events',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'transcript_format',
        label: 'Output Format',
        type: 'enum',
        required: false,
        default: 'text',
        options: [
          { label: 'Plain Text', value: 'text' },
          { label: 'SRT Subtitles', value: 'srt' },
          { label: 'VTT Subtitles', value: 'vtt' },
        ],
      },
    ],
  },

  'demucs': {
    id: 'demucs',
    displayName: 'Demucs (Stem Separation)',
    category: 'audio-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/demucs',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'audio', label: 'Audio', dataType: 'Audio', required: true },
    ],
    outputPorts: [
      { id: 'vocals', label: 'Vocals', dataType: 'Audio', required: false },
      { id: 'drums', label: 'Drums', dataType: 'Audio', required: false },
      { id: 'bass', label: 'Bass', dataType: 'Audio', required: false },
      { id: 'other', label: 'Other', dataType: 'Audio', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'enum',
        required: false,
        default: 'htdemucs_ft',
        options: [
          { label: 'HT-Demucs FT (best 4-stem)', value: 'htdemucs_ft' },
          { label: 'HT-Demucs', value: 'htdemucs' },
          { label: 'HDemucs MMI', value: 'hdemucs_mmi' },
          { label: 'MDX', value: 'mdx' },
          { label: 'MDX Extra', value: 'mdx_extra' },
        ],
      },
      {
        key: 'shifts',
        label: 'Quality (Shifts)',
        type: 'integer',
        required: false,
        default: 1,
        min: 1,
        max: 10,
      },
      {
        key: 'overlap',
        label: 'Overlap',
        type: 'float',
        required: false,
        default: 0.25,
        min: 0,
        max: 1,
        step: 0.05,
      },
      {
        key: 'output_format',
        label: 'Output Format',
        type: 'enum',
        required: false,
        default: 'mp3',
        options: [
          { label: 'MP3', value: 'mp3' },
          { label: 'WAV', value: 'wav' },
        ],
      },
    ],
  },

  'mmaudio-v2': {
    id: 'mmaudio-v2',
    displayName: 'MMAudio V2 (Video Foley)',
    category: 'audio-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/mmaudio-v2',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: true },
      { id: 'prompt', label: 'Audio Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'video', label: 'Video (with audio)', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'negative_prompt',
        label: 'Negative Prompt',
        type: 'string',
        required: false,
        placeholder: 'e.g. music, talking, static',
      },
      {
        key: 'duration',
        label: 'Duration (seconds)',
        type: 'integer',
        required: false,
        default: 8,
        min: 1,
        max: 30,
      },
      {
        key: 'num_steps',
        label: 'Steps',
        type: 'integer',
        required: false,
        default: 25,
        min: 10,
        max: 100,
      },
      {
        key: 'cfg_strength',
        label: 'Guidance (CFG)',
        type: 'float',
        required: false,
        default: 4.5,
        min: 1,
        max: 20,
        step: 0.5,
      },
      {
        key: 'mask_away_clip',
        label: 'Replace existing audio',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
  },

  'ace-step': {
    id: 'ace-step',
    displayName: 'ACE-Step (Music + Vocals)',
    category: 'audio-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/ace-step',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [],
    outputPorts: [
      { id: 'audio', label: 'Audio', dataType: 'Audio', required: false },
    ],
    params: [
      {
        key: 'tags',
        label: 'Style Tags',
        type: 'string',
        required: true,
        placeholder: 'e.g. lofi hiphop, chill, jazzy piano, 90 BPM',
      },
      {
        key: 'lyrics',
        label: 'Lyrics',
        type: 'textarea',
        required: false,
        default: '[instrumental]',
        placeholder: '[Verse] lyrics, or [instrumental] for no vocals',
      },
      {
        key: 'duration',
        label: 'Duration (seconds)',
        type: 'integer',
        required: false,
        default: 30,
        min: 5,
        max: 60,
      },
      {
        key: 'number_of_steps',
        label: 'Steps',
        type: 'integer',
        required: false,
        default: 27,
        min: 1,
        max: 200,
      },
      {
        key: 'guidance_scale',
        label: 'Guidance Scale',
        type: 'float',
        required: false,
        default: 15,
        min: 1,
        max: 30,
        step: 0.5,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
  },

  'stable-audio-25': {
    id: 'stable-audio-25',
    displayName: 'Stable Audio 2.5',
    category: 'audio-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/stable-audio-25/text-to-audio',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'audio', label: 'Audio', dataType: 'Audio', required: false },
    ],
    params: [
      {
        key: 'seconds_total',
        label: 'Duration (seconds)',
        type: 'integer',
        required: false,
        default: 60,
        min: 1,
        max: 190,
      },
      {
        key: 'num_inference_steps',
        label: 'Steps',
        type: 'integer',
        required: false,
        default: 8,
        min: 1,
        max: 50,
      },
      {
        key: 'guidance_scale',
        label: 'Guidance Scale',
        type: 'float',
        required: false,
        default: 7.5,
        min: 0,
        max: 20,
        step: 0.5,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
  },

  'flux-1-1-ultra': {
    id: 'flux-1-1-ultra',
    displayName: 'FLUX 1.1 Ultra',
    category: 'image-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/flux-pro/v1.1-ultra',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'image', label: 'Image Guide', dataType: 'Image', required: false },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [],
    sharedParams: [
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: '16:9',
        options: [
          { label: '21:9', value: '21:9' },
          { label: '16:9', value: '16:9' },
          { label: '4:3', value: '4:3' },
          { label: '3:2', value: '3:2' },
          { label: '1:1', value: '1:1' },
          { label: '2:3', value: '2:3' },
          { label: '3:4', value: '3:4' },
          { label: '9:16', value: '9:16' },
          { label: '9:21', value: '9:21' },
        ],
      },
      {
        key: 'num_images',
        label: 'Count',
        type: 'integer',
        required: false,
        default: 1,
        min: 1,
        max: 4,
      },
    ],
    falParams: [
      {
        key: 'safety_tolerance',
        label: 'Safety Tolerance',
        type: 'enum',
        required: false,
        default: '2',
        options: [
          { label: '1 (Strict)', value: '1' },
          { label: '2', value: '2' },
          { label: '3', value: '3' },
          { label: '4', value: '4' },
          { label: '5', value: '5' },
          { label: '6 (Permissive)', value: '6' },
        ],
      },
      {
        key: 'enhance_prompt',
        label: 'Enhance Prompt',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'output_format',
        label: 'Format',
        type: 'enum',
        required: false,
        default: 'jpeg',
        options: [
          { label: 'JPEG', value: 'jpeg' },
          { label: 'PNG', value: 'png' },
        ],
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
      {
        key: 'image_prompt_strength',
        label: 'Image Influence',
        type: 'float',
        required: false,
        default: 0.1,
        min: 0,
        max: 1,
        step: 0.05,
      },
    ],
  },

  'text-input': {
    id: 'text-input',
    displayName: 'Text Input',
    category: 'utility',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    inputPorts: [],
    outputPorts: [
      { id: 'text', label: 'Text', dataType: 'Text', required: false },
    ],
    params: [
      {
        key: 'value',
        label: 'Text',
        type: 'textarea',
        required: true,
        default: '',
        placeholder: 'Enter text or prompt...',
      },
    ],
  },

  'image-input': {
    id: 'image-input',
    displayName: 'Image Input',
    category: 'utility',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    inputPorts: [],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'filePath',
        label: 'File',
        type: 'file',
        required: true,
        default: '',
      },
    ],
  },

  'style-reference': {
    id: 'style-reference',
    displayName: 'Style Reference',
    category: 'utility',
    apiProvider: 'google',
    apiEndpoint: '/v1beta/models/gemini-2.5-flash:generateContent',
    envKeyName: 'GOOGLE_API_KEY',
    executionPattern: 'sync',
    inputPorts: [],
    outputPorts: [
      { id: 'image', label: 'Reference', dataType: 'Image', required: false },
      { id: 'style_description', label: 'Style', dataType: 'Text', required: false },
    ],
    params: [
      { key: 'filePath', label: 'Reference Image', type: 'file', required: true, default: '' },
      {
        key: 'mode',
        label: 'Description Mode',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto (Gemini)', value: 'auto' },
          { label: 'Manual', value: 'manual' },
          { label: 'Image only', value: 'passthrough' },
        ],
      },
      {
        key: 'manual_description',
        label: 'Description',
        type: 'textarea',
        required: false,
        default: '',
        placeholder: 'e.g. wabi-sabi minimalism, warm tungsten lighting, grainy 35mm film',
        visibleWhen: { mode: ['manual'] },
      },
      {
        key: 'focus',
        label: 'Focus',
        type: 'enum',
        required: false,
        default: 'all',
        visibleWhen: { mode: ['auto'] },
        options: [
          { label: 'All (palette + lighting + medium + mood)', value: 'all' },
          { label: 'Palette only', value: 'palette' },
          { label: 'Lighting only', value: 'lighting' },
          { label: 'Medium / texture only', value: 'medium' },
        ],
      },
      { key: 'strength', label: 'Strength', type: 'float', required: false, default: 0.7, min: 0, max: 1, step: 0.05 },
    ],
  },

  'video-edit': {
    id: 'video-edit',
    displayName: 'Video Edit',
    category: 'utility',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'video_in', label: 'Source Video', dataType: 'Video', required: true },
    ],
    outputPorts: [
      { id: 'video', label: 'Edited Video', dataType: 'Video', required: false },
    ],
    params: [],
  },

  'remotion-node': {
    id: 'remotion-node',
    displayName: 'Remotion Composition',
    category: 'utility',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'sources', label: 'Track Sources', dataType: 'Any', required: false },
    ],
    outputPorts: [
      { id: 'video', label: 'Rendered Video', dataType: 'Video', required: false },
    ],
    params: [],
  },

  'cinema-color': {
    id: 'cinema-color',
    displayName: 'Cinema Color',
    category: 'cinematic',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    inputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      { key: 'palette', label: 'Palette', type: 'palette', required: false, default: [] },
      { key: 'strength', label: 'Strength', type: 'float', required: false, default: 0.7, min: 0, max: 1, step: 0.05 },
      {
        key: 'method',
        label: 'Method',
        type: 'enum',
        required: false,
        default: 'lab-transfer',
        options: [
          { label: 'Lab Transfer', value: 'lab-transfer' },
          { label: 'Reinhard', value: 'reinhard' },
          { label: 'Histogram', value: 'histogram' },
        ],
      },
      { key: 'source_image', label: 'Palette Source', type: 'file', required: false, default: '' },
    ],
  },

  'cinema-look': {
    id: 'cinema-look',
    displayName: 'Cinema Look',
    category: 'cinematic',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    inputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'preset',
        label: 'Preset',
        type: 'enum',
        required: false,
        default: 'custom',
        options: [
          { label: 'Kodak Portra', value: 'kodak-portra' },
          { label: 'Fuji 400H', value: 'fuji-400h' },
          { label: 'CineStill 800T', value: 'cinestill-800t' },
          { label: 'B&W Tri-X', value: 'bw-tri-x' },
          { label: 'Teal & Orange', value: 'teal-orange' },
          { label: 'Custom', value: 'custom' },
        ],
      },
      { key: 'grain', label: 'Grain', type: 'float', required: false, default: 0.2, min: 0, max: 1, step: 0.05, visibleWhen: { preset: ['custom'] } },
      { key: 'halation', label: 'Halation', type: 'float', required: false, default: 0.2, min: 0, max: 1, step: 0.05, visibleWhen: { preset: ['custom'] } },
      { key: 'vignette', label: 'Vignette', type: 'float', required: false, default: 0.25, min: 0, max: 1, step: 0.05, visibleWhen: { preset: ['custom'] } },
      { key: 'contrast', label: 'Contrast', type: 'float', required: false, default: 0, min: -1, max: 1, step: 0.05, visibleWhen: { preset: ['custom'] } },
      { key: 'saturation', label: 'Saturation', type: 'float', required: false, default: 0, min: -1, max: 1, step: 0.05, visibleWhen: { preset: ['custom'] } },
      { key: 'temperature', label: 'Temperature', type: 'float', required: false, default: 0, min: -1, max: 1, step: 0.05, visibleWhen: { preset: ['custom'] } },
      { key: 'lut', label: 'LUT (.cube)', type: 'file', required: false, default: '' },
    ],
  },

  'cinema-scene': {
    id: 'cinema-scene',
    displayName: 'Cinema Scene',
    category: 'cinematic',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'character_refs', label: 'Character Refs', dataType: 'Image', required: false, multiple: true },
      { id: 'character', label: 'Character', dataType: 'Character', required: false },
    ],
    // Output ports are dynamic — one Image port per shot, written at runtime from
    // the editor-managed scene spec. Starts empty (mirrors remotion-node).
    outputPorts: [],
    // The `scene` spec (a complex object: base model, aspect ratio, shots) is
    // authored via the Cinema Studio, not a generic param control. It's declared
    // here so the backend validator (_valid_param_keys) accepts it as a known key
    // — agents and the Studio both persist it via PUT/POST /api/graph/node — and
    // marked `hidden` so the Inspector never renders it as a broken editable
    // field. The handler (cinema_scene.py) reads params.get("scene") unchanged.
    params: [
      { key: 'scene', label: 'Scene', type: 'string', required: false, hidden: true },
    ],
  },

  'character': {
    id: 'character',
    displayName: 'Character',
    category: 'character',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    // No inputs — the identity asset is loaded from the project Character store
    // by id (params._characterId, a `_`-prefixed runtime ref, not a declared
    // model param), not wired in on a port.
    inputPorts: [],
    outputPorts: [
      { id: 'character', label: 'Character', dataType: 'Character', required: false },
    ],
    params: [
      {
        key: 'override_prompt',
        label: 'Override Prompt',
        type: 'textarea',
        required: false,
        default: '',
        placeholder: 'Optional per-shot direction: pose, expression, wardrobe, framing',
      },
      // Optional extra Image refs layered on top of the stored referenceViews.
      { key: 'override_refs', label: 'Override Refs', type: 'file', required: false, default: '' },
      // Empty string = inherit the Character's stored consistencyStrength.
      { key: 'strength_override', label: 'Strength Override', type: 'float', required: false, default: '', min: 0, max: 1, step: 0.05 },
    ],
  },

  'nebula-moodboard': {
    id: 'nebula-moodboard',
    displayName: 'Moodboard',
    category: 'moodboard',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    inputPorts: [],
    outputPorts: [
      { id: 'moodboard', label: 'Moodboard', dataType: 'Moodboard', required: false },
      { id: 'style_brief', label: 'Style Brief', dataType: 'Text', required: false },
      { id: 'negative_prompt', label: 'Negative Prompt', dataType: 'Text', required: false },
      { id: 'representative_images', label: 'Images', dataType: 'Array', required: false },
      { id: 'palette', label: 'Palette', dataType: 'Array', required: false },
    ],
    params: [
      { key: 'moodboard', label: 'Moodboard', type: 'string', required: false, hidden: true },
    ],
  },

  'preview': {
    id: 'preview',
    displayName: 'Preview',
    category: 'utility',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    inputPorts: [
      { id: 'input', label: 'Input', dataType: 'Any', required: true },
    ],
    outputPorts: [],
    params: [],
  },

  'combine-text': {
    id: 'combine-text',
    displayName: 'Combine Text',
    category: 'utility',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    inputPorts: [
      { id: 'text1', label: 'Text 1', dataType: 'Text', required: true },
      { id: 'text2', label: 'Text 2', dataType: 'Text', required: false },
      { id: 'text3', label: 'Text 3', dataType: 'Text', required: false },
    ],
    outputPorts: [
      { id: 'text', label: 'Text', dataType: 'Text', required: false },
    ],
    params: [
      {
        key: 'separator',
        label: 'Separator',
        type: 'string',
        required: false,
        default: '\\n',
        placeholder: 'e.g. \\n or " | " or ", "',
      },
      {
        key: 'template',
        label: 'Template',
        type: 'textarea',
        required: false,
        default: '',
        placeholder: 'Optional: use {text1}, {text2}, {text3} placeholders',
      },
    ],
  },

  'router': {
    id: 'router',
    displayName: 'Router',
    category: 'utility',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    inputPorts: [
      { id: 'input', label: 'Input', dataType: 'Any', required: true },
    ],
    outputPorts: [
      { id: 'out1', label: 'Out 1', dataType: 'Any', required: false },
      { id: 'out2', label: 'Out 2', dataType: 'Any', required: false },
      { id: 'out3', label: 'Out 3', dataType: 'Any', required: false },
    ],
    params: [],
  },

  'reroute': {
    id: 'reroute',
    displayName: 'Reroute',
    category: 'utility',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    inputPorts: [
      { id: 'input', label: 'Input', dataType: 'Any', required: true },
    ],
    outputPorts: [
      { id: 'output', label: 'Output', dataType: 'Any', required: false },
    ],
    params: [],
  },

  'openrouter-universal': {
    id: 'openrouter-universal',
    displayName: 'OpenRouter',
    category: 'universal',
    apiProvider: 'openrouter',
    apiEndpoint: 'https://openrouter.ai/api/v1/chat/completions',
    envKeyName: 'OPENROUTER_API_KEY',
    executionPattern: 'stream',
    inputPorts: [
      { id: 'messages', label: 'Messages', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'text', label: 'Text', dataType: 'Text', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'string',
        required: true,
        default: '',
        placeholder: 'Loading models...',
      },
      {
        key: 'temperature',
        label: 'Temperature',
        type: 'float',
        required: false,
        default: 1.0,
        min: 0,
        max: 2,
        step: 0.1,
      },
      {
        key: 'max_tokens',
        label: 'Max Tokens',
        type: 'integer',
        required: false,
        default: 4096,
        min: 1,
        max: 200000,
      },
      {
        key: 'response_format',
        label: 'Response Format',
        type: 'enum',
        required: false,
        default: 'text',
        options: [
          { label: 'Text', value: 'text' },
          { label: 'JSON', value: 'json_object' },
        ],
      },
      {
        key: 'prompt_caching',
        label: 'Prompt Caching',
        type: 'boolean',
        required: false,
        default: false,
      },
    ],
  },

  'nous-portal-universal': {
    id: 'nous-portal-universal',
    displayName: 'Nous Portal',
    category: 'universal',
    apiProvider: 'nous',
    apiEndpoint: 'https://inference-api.nousresearch.com/v1/chat/completions',
    // No env-key field — auth is OAuth, stored in ~/.hermes/auth.json after
    // `hermes auth`. The backend reads it; the frontend doesn't need a key.
    envKeyName: [],
    executionPattern: 'stream',
    inputPorts: [
      { id: 'messages', label: 'Messages', dataType: 'Text', required: true },
      { id: 'images', label: 'Images', dataType: 'Image', required: false, multiple: true },
    ],
    outputPorts: [
      { id: 'text', label: 'Text', dataType: 'Text', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'string',
        required: true,
        default: '',
        placeholder: 'Loading models…',
      },
      {
        key: 'temperature',
        label: 'Temperature',
        type: 'float',
        required: false,
        default: 1.0,
        min: 0,
        max: 2,
        step: 0.1,
      },
      {
        key: 'max_tokens',
        label: 'Max Tokens',
        type: 'integer',
        required: false,
        default: 4096,
        min: 1,
        max: 200000,
      },
    ],
  },

  'replicate-universal': {
    id: 'replicate-universal',
    displayName: 'Replicate',
    category: 'universal',
    apiProvider: 'replicate',
    apiEndpoint: 'https://api.replicate.com/v1/predictions',
    envKeyName: 'REPLICATE_API_TOKEN',
    executionPattern: 'async-poll',
    inputPorts: [],
    outputPorts: [],
    params: [
      {
        key: 'model_id',
        label: 'Model ID',
        type: 'string',
        required: true,
        default: '',
        placeholder: 'owner/name (e.g. stability-ai/sdxl)',
      },
    ],
  },

  'fal-universal': {
    id: 'fal-universal',
    displayName: 'FAL',
    category: 'universal',
    apiProvider: 'fal',
    apiEndpoint: 'https://queue.fal.run',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
      { id: 'audio', label: 'Audio', dataType: 'Audio', required: false },
      { id: 'mesh', label: 'Mesh', dataType: 'Mesh', required: false },
    ],
    params: [
      {
        key: 'endpoint_id',
        label: 'Endpoint',
        type: 'string',
        required: true,
        default: 'fal-ai/flux-pro/v1.1-ultra',
        placeholder: 'fal-ai/flux-pro/v1.1-ultra',
      },
    ],
  },

  // dalle-3-generate removed 2026-06: OpenAI shut down dall-e-2/dall-e-3 on 2026-05-12.
  // gpt-image-1 / gpt-image-1.5 / gpt-image-2 nodes are the replacements.

  'gpt-4o-chat': {
    id: 'gpt-4o-chat',
    displayName: 'OpenAI Chat',
    category: 'text-gen',
    apiProvider: 'openai',
    apiEndpoint: '/v1/chat/completions',
    envKeyName: 'OPENAI_API_KEY',
    executionPattern: 'stream',
    inputPorts: [
      { id: 'messages', label: 'Messages', dataType: 'Text', required: true },
      { id: 'images', label: 'Images', dataType: 'Image', required: false, multiple: true },
    ],
    outputPorts: [
      { id: 'text', label: 'Text', dataType: 'Text', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'enum',
        required: true,
        default: 'gpt-5.4',
        options: [
          { label: 'GPT-5.5 (flagship)', value: 'gpt-5.5' },
          { label: 'GPT-5.4', value: 'gpt-5.4' },
          { label: 'GPT-5.4 Mini', value: 'gpt-5.4-mini' },
          { label: 'GPT-5.4 Nano', value: 'gpt-5.4-nano' },
          { label: 'GPT-4o (legacy)', value: 'gpt-4o' },
          { label: 'GPT-4o Mini (legacy)', value: 'gpt-4o-mini' },
          { label: 'GPT-4.1 (legacy)', value: 'gpt-4.1' },
          { label: 'GPT-4.1 Mini (legacy)', value: 'gpt-4.1-mini' },
          { label: 'GPT-4.1 Nano (legacy, sunsets 2026-10-23)', value: 'gpt-4.1-nano' },
        ],
      },
      {
        key: 'reasoning_effort',
        label: 'Reasoning Effort',
        type: 'enum',
        required: false,
        default: 'medium',
        options: [
          { label: 'None', value: 'none' },
          { label: 'Low', value: 'low' },
          { label: 'Medium', value: 'medium' },
          { label: 'High', value: 'high' },
          { label: 'X-High', value: 'xhigh' },
        ],
        visibleWhen: { model: ['gpt-5.5', 'gpt-5.4', 'gpt-5.4-mini', 'gpt-5.4-nano'] },
      },
      {
        key: 'max_completion_tokens',
        label: 'Max Tokens',
        type: 'integer',
        required: false,
        default: 4096,
        min: 1,
        max: 128000,
      },
      {
        key: 'temperature',
        label: 'Temperature',
        type: 'float',
        required: false,
        default: 1,
        min: 0,
        max: 2,
        step: 0.1,
        visibleWhen: { model: ['gpt-4o', 'gpt-4o-mini', 'gpt-4.1', 'gpt-4.1-mini', 'gpt-4.1-nano'] },
      },
      {
        key: 'top_p',
        label: 'Top P',
        type: 'float',
        required: false,
        min: 0,
        max: 1,
        step: 0.05,
        placeholder: 'Default',
        visibleWhen: { model: ['gpt-4o', 'gpt-4o-mini', 'gpt-4.1', 'gpt-4.1-mini', 'gpt-4.1-nano'] },
      },
      {
        key: 'frequency_penalty',
        label: 'Frequency Penalty',
        type: 'float',
        required: false,
        default: 0,
        min: -2,
        max: 2,
        step: 0.1,
        visibleWhen: { model: ['gpt-4o', 'gpt-4o-mini', 'gpt-4.1', 'gpt-4.1-mini', 'gpt-4.1-nano'] },
      },
      {
        key: 'presence_penalty',
        label: 'Presence Penalty',
        type: 'float',
        required: false,
        default: 0,
        min: -2,
        max: 2,
        step: 0.1,
        visibleWhen: { model: ['gpt-4o', 'gpt-4o-mini', 'gpt-4.1', 'gpt-4.1-mini', 'gpt-4.1-nano'] },
      },
      {
        key: 'response_format',
        label: 'Response Format',
        type: 'enum',
        required: false,
        default: 'text',
        options: [
          { label: 'Text', value: 'text' },
          { label: 'JSON', value: 'json_object' },
        ],
      },
    ],
  },

  'gemini-chat': {
    id: 'gemini-chat',
    displayName: 'Gemini',
    category: 'text-gen',
    apiProvider: 'google',
    apiEndpoint: '/v1beta/models/{model}:streamGenerateContent',
    envKeyName: 'GOOGLE_API_KEY',
    executionPattern: 'stream',
    inputPorts: [
      { id: 'messages', label: 'Messages', dataType: 'Text', required: true },
      { id: 'images', label: 'Images', dataType: 'Image', required: false, multiple: true },
    ],
    outputPorts: [
      { id: 'text', label: 'Text', dataType: 'Text', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'enum',
        required: true,
        default: 'gemini-3.5-flash',
        options: [
          { label: 'Gemini 3.5 Flash', value: 'gemini-3.5-flash' },
          { label: 'Gemini 3.1 Pro (preview)', value: 'gemini-3.1-pro-preview' },
          { label: 'Gemini 3 Flash (preview)', value: 'gemini-3-flash-preview' },
          { label: 'Gemini 3.1 Flash-Lite', value: 'gemini-3.1-flash-lite' },
          { label: 'Gemini 2.5 Pro', value: 'gemini-2.5-pro' },
          { label: 'Gemini 2.5 Flash', value: 'gemini-2.5-flash' },
          { label: 'Gemini 2.5 Flash-Lite', value: 'gemini-2.5-flash-lite' },
        ],
      },
      {
        key: 'max_tokens',
        label: 'Max Tokens',
        type: 'integer',
        required: false,
        default: 8192,
        min: 1,
        max: 65535,
      },
      {
        key: 'temperature',
        label: 'Temperature',
        type: 'float',
        required: false,
        default: 1,
        min: 0,
        max: 2,
        step: 0.1,
      },
      {
        key: 'system',
        label: 'System Prompt',
        type: 'textarea',
        required: false,
        default: '',
        placeholder: 'System instructions...',
      },
      {
        key: 'thinkingLevel',
        label: 'Thinking Level',
        type: 'enum',
        required: false,
        default: '',
        visibleWhen: { model: ['gemini-3.5-flash', 'gemini-3.1-pro-preview', 'gemini-3-flash-preview', 'gemini-3.1-flash-lite'] },
        options: [
          { label: 'Default', value: '' },
          { label: 'Minimal', value: 'minimal' },
          { label: 'Low', value: 'low' },
          { label: 'Medium', value: 'medium' },
          { label: 'High', value: 'high' },
        ],
      },
      {
        key: 'thinkingBudget',
        label: 'Thinking Budget',
        type: 'integer',
        required: false,
        visibleWhen: { model: ['gemini-2.5-pro', 'gemini-2.5-flash', 'gemini-2.5-flash-lite'] },
        placeholder: 'Token budget for thinking',
        min: 0,
        max: 65536,
      },
      {
        key: 'top_p',
        label: 'Top P',
        type: 'float',
        required: false,
        min: 0,
        max: 1,
        step: 0.05,
        placeholder: 'Default',
      },
      {
        key: 'top_k',
        label: 'Top K',
        type: 'integer',
        required: false,
        placeholder: '64',
      },
      {
        key: 'stop_sequences',
        label: 'Stop Sequences',
        type: 'string',
        required: false,
        placeholder: 'Comma-separated',
      },
      {
        key: 'response_format',
        label: 'Response Format',
        type: 'enum',
        required: false,
        default: 'text/plain',
        options: [
          { label: 'Text', value: 'text/plain' },
          { label: 'JSON', value: 'application/json' },
        ],
      },
    ],
  },

  'imagen-4-generate': {
    id: 'imagen-4-generate',
    displayName: 'Imagen 4',
    category: 'image-gen',
    apiProvider: 'google',
    apiEndpoint: '/v1beta/models/{model}:predict',
    envKeyName: 'GOOGLE_API_KEY',
    executionPattern: 'sync',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'enum',
        required: true,
        default: 'imagen-4.0-generate-001',
        options: [
          { label: 'Imagen 4', value: 'imagen-4.0-generate-001' },
          { label: 'Imagen 4 Ultra', value: 'imagen-4.0-ultra-generate-001' },
          { label: 'Imagen 4 Fast', value: 'imagen-4.0-fast-generate-001' },
        ],
      },
      {
        key: 'aspectRatio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: '1:1',
        options: [
          { label: '1:1', value: '1:1' },
          { label: '4:3', value: '4:3' },
          { label: '3:4', value: '3:4' },
          { label: '16:9', value: '16:9' },
          { label: '9:16', value: '9:16' },
        ],
      },
      {
        key: 'numberOfImages',
        label: 'Count',
        type: 'integer',
        required: false,
        default: 1,
        min: 1,
        max: 4,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
      {
        key: 'enhancePrompt',
        label: 'Enhance Prompt',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'imageSize',
        label: 'Image Size',
        type: 'enum',
        required: false,
        default: '1K',
        visibleWhen: { model: ['imagen-4.0-generate-001', 'imagen-4.0-ultra-generate-001'] },
        options: [
          { label: '1K', value: '1K' },
          { label: '2K', value: '2K' },
        ],
      },
      {
        key: 'personGeneration',
        label: 'Person Generation',
        type: 'enum',
        required: false,
        default: 'allow_adult',
        options: [
          { label: 'Allow All', value: 'allow_all' },
          { label: 'Allow Adult', value: 'allow_adult' },
          { label: "Don't Allow", value: 'dont_allow' },
        ],
      },
    ],
  },

  'kling-v2-1': {
    id: 'kling-v2-1',
    displayName: 'Kling v2.1',
    category: 'video-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/kling-video/v2.1/pro/image-to-video',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: false },
      { id: 'tail_image', label: 'End Frame', dataType: 'Image', required: false },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'duration',
        label: 'Duration',
        type: 'enum',
        required: false,
        default: '5',
        options: [
          { label: '5 seconds', value: '5' },
          { label: '10 seconds', value: '10' },
        ],
      },
      {
        key: 'negative_prompt',
        label: 'Negative Prompt',
        type: 'string',
        required: false,
        default: 'blur, distort, and low quality',
      },
      {
        key: 'cfg_scale',
        label: 'CFG Scale',
        type: 'float',
        required: false,
        default: 0.5,
        min: 0,
        max: 1,
        step: 0.1,
      },
    ],
  },

  'sora-2': {
    id: 'sora-2',
    displayName: "Sora 2 (sunsets Sep '26)",
    category: 'video-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/sora-2/text-to-video',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'resolution',
        label: 'Resolution',
        type: 'enum',
        required: false,
        default: '720p',
        options: [
          { label: '720p', value: '720p' },
          { label: '1080p', value: '1080p' },
        ],
      },
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: '16:9',
        options: [
          { label: '16:9', value: '16:9' },
          { label: '9:16', value: '9:16' },
        ],
      },
      {
        key: 'duration',
        label: 'Duration (s)',
        type: 'enum',
        required: false,
        default: 4,
        options: [
          { label: '4s', value: 4 },
          { label: '8s', value: 8 },
          { label: '12s', value: 12 },
          { label: '16s', value: 16 },
          { label: '20s', value: 20 },
        ],
      },
    ],
  },

  'nano-banana': {
    id: 'nano-banana',
    displayName: 'Nano Banana',
    category: 'image-gen',
    apiProvider: 'google',
    apiEndpoint: '/v1beta/models/{model}:generateContent',
    envKeyName: 'GOOGLE_API_KEY',
    executionPattern: 'sync',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'images', label: 'Images', dataType: 'Image', required: false, multiple: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
      { id: 'text', label: 'Text', dataType: 'Text', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'enum',
        required: false,
        default: 'gemini-3.1-flash-image-preview',
        options: [
          { label: 'Nano Banana 2 (3.1 Flash)', value: 'gemini-3.1-flash-image-preview' },
          { label: 'Nano Banana Pro (3 Pro)', value: 'gemini-3-pro-image-preview' },
          { label: 'Nano Banana (2.5 Flash)', value: 'gemini-2.5-flash-image' },
        ],
      },
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: '1:1',
        options: [
          { label: '1:1', value: '1:1' },
          { label: '16:9', value: '16:9' },
          { label: '9:16', value: '9:16' },
          { label: '4:3', value: '4:3' },
          { label: '3:4', value: '3:4' },
          { label: '3:2', value: '3:2' },
          { label: '2:3', value: '2:3' },
          { label: '5:4', value: '5:4' },
          { label: '4:5', value: '4:5' },
          { label: '21:9', value: '21:9' },
          { label: '1:4', value: '1:4', visibleWhen: { model: ['gemini-3.1-flash-image-preview'] } },
          { label: '4:1', value: '4:1', visibleWhen: { model: ['gemini-3.1-flash-image-preview'] } },
          { label: '1:8', value: '1:8', visibleWhen: { model: ['gemini-3.1-flash-image-preview'] } },
          { label: '8:1', value: '8:1', visibleWhen: { model: ['gemini-3.1-flash-image-preview'] } },
        ],
      },
      {
        key: 'imageSize',
        label: 'Image Size',
        type: 'enum',
        required: false,
        default: '1K',
        visibleWhen: { model: ['gemini-3.1-flash-image-preview', 'gemini-3-pro-image-preview'] },
        options: [
          { label: '512', value: '512', visibleWhen: { model: ['gemini-3.1-flash-image-preview'] } },
          { label: '1K', value: '1K' },
          { label: '2K', value: '2K' },
          { label: '4K', value: '4K' },
        ],
      },
    ],
  },

  'lyria-3': {
    id: 'lyria-3',
    displayName: 'Lyria 3',
    category: 'audio-gen',
    apiProvider: 'google',
    apiEndpoint: '/v1beta/models/{model}:generateContent',
    envKeyName: 'GOOGLE_API_KEY',
    executionPattern: 'sync',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'images', label: 'Images', dataType: 'Image', required: false, multiple: true },
    ],
    outputPorts: [
      { id: 'audio', label: 'Audio', dataType: 'Audio', required: false },
      { id: 'text', label: 'Lyrics', dataType: 'Text', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'enum',
        required: true,
        default: 'lyria-3-clip-preview',
        options: [
          { label: 'Lyria 3 Clip (30s)', value: 'lyria-3-clip-preview' },
          { label: 'Lyria 3 Pro (full song)', value: 'lyria-3-pro-preview' },
        ],
      },
      {
        key: 'outputFormat',
        label: 'Output Format',
        type: 'enum',
        required: false,
        default: 'mp3',
        visibleWhen: { model: ['lyria-3-pro-preview'] },
        options: [
          { label: 'MP3', value: 'mp3' },
          { label: 'WAV', value: 'wav' },
        ],
      },
    ],
  },

  'gemini-tts': {
    id: 'gemini-tts',
    displayName: 'Gemini TTS',
    category: 'audio-gen',
    apiProvider: 'google',
    apiEndpoint: '/v1beta/models/{model}:generateContent',
    envKeyName: 'GOOGLE_API_KEY',
    executionPattern: 'sync',
    inputPorts: [
      { id: 'text', label: 'Text', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'audio', label: 'Audio', dataType: 'Audio', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'enum',
        required: false,
        default: 'gemini-2.5-flash-preview-tts',
        options: [
          { label: '3.1 Flash TTS (preview)', value: 'gemini-3.1-flash-tts-preview' },
          { label: '2.5 Flash TTS', value: 'gemini-2.5-flash-preview-tts' },
          { label: '2.5 Pro TTS', value: 'gemini-2.5-pro-preview-tts' },
        ],
      },
      {
        key: 'voiceName',
        label: 'Voice',
        type: 'enum',
        required: false,
        default: 'Kore',
        options: [
          { label: 'Zephyr — Bright', value: 'Zephyr' },
          { label: 'Puck — Upbeat', value: 'Puck' },
          { label: 'Charon — Informative', value: 'Charon' },
          { label: 'Kore — Firm', value: 'Kore' },
          { label: 'Fenrir — Excitable', value: 'Fenrir' },
          { label: 'Leda — Youthful', value: 'Leda' },
          { label: 'Orus — Firm', value: 'Orus' },
          { label: 'Aoede — Breezy', value: 'Aoede' },
          { label: 'Callirrhoe — Easy-going', value: 'Callirrhoe' },
          { label: 'Autonoe — Bright', value: 'Autonoe' },
          { label: 'Enceladus — Breathy', value: 'Enceladus' },
          { label: 'Iapetus — Clear', value: 'Iapetus' },
          { label: 'Umbriel — Easy-going', value: 'Umbriel' },
          { label: 'Algieba — Smooth', value: 'Algieba' },
          { label: 'Despina — Smooth', value: 'Despina' },
          { label: 'Erinome — Clear', value: 'Erinome' },
          { label: 'Algenib — Gravelly', value: 'Algenib' },
          { label: 'Rasalgethi — Informative', value: 'Rasalgethi' },
          { label: 'Laomedeia — Upbeat', value: 'Laomedeia' },
          { label: 'Achernar — Soft', value: 'Achernar' },
          { label: 'Alnilam — Firm', value: 'Alnilam' },
          { label: 'Schedar — Even', value: 'Schedar' },
          { label: 'Gacrux — Mature', value: 'Gacrux' },
          { label: 'Pulcherrima — Forward', value: 'Pulcherrima' },
          { label: 'Achird — Friendly', value: 'Achird' },
          { label: 'Zubenelgenubi — Casual', value: 'Zubenelgenubi' },
          { label: 'Vindemiatrix — Gentle', value: 'Vindemiatrix' },
          { label: 'Sadachbia — Lively', value: 'Sadachbia' },
          { label: 'Sadaltager — Knowledgeable', value: 'Sadaltager' },
          { label: 'Sulafat — Warm', value: 'Sulafat' },
        ],
      },
    ],
  },

  'gemini-embeddings': {
    id: 'gemini-embeddings',
    displayName: 'Gemini Embeddings',
    category: 'utility',
    apiProvider: 'google',
    apiEndpoint: '/v1beta/models/{model}:embedContent',
    envKeyName: 'GOOGLE_API_KEY',
    executionPattern: 'sync',
    inputPorts: [
      { id: 'text', label: 'Text', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'embedding', label: 'Embedding', dataType: 'Text', required: false },
      { id: 'dimensions', label: 'Dimensions', dataType: 'Text', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'enum',
        required: false,
        default: 'gemini-embedding-001',
        options: [
          { label: 'Embedding 001 (text)', value: 'gemini-embedding-001' },
          { label: 'Embedding 2 (multimodal)', value: 'gemini-embedding-2-preview' },
        ],
      },
      {
        key: 'taskType',
        label: 'Task Type',
        type: 'enum',
        required: false,
        default: 'SEMANTIC_SIMILARITY',
        options: [
          { label: 'Semantic Similarity', value: 'SEMANTIC_SIMILARITY' },
          { label: 'Retrieval Query', value: 'RETRIEVAL_QUERY' },
          { label: 'Retrieval Document', value: 'RETRIEVAL_DOCUMENT' },
          { label: 'Classification', value: 'CLASSIFICATION' },
          { label: 'Clustering', value: 'CLUSTERING' },
          { label: 'Code Retrieval', value: 'CODE_RETRIEVAL_QUERY' },
          { label: 'Question Answering', value: 'QUESTION_ANSWERING' },
          { label: 'Fact Verification', value: 'FACT_VERIFICATION' },
        ],
      },
      {
        key: 'outputDimensionality',
        label: 'Dimensions',
        type: 'enum',
        required: false,
        default: '768',
        options: [
          { label: '768', value: '768' },
          { label: '1536', value: '1536' },
          { label: '3072', value: '3072' },
        ],
      },
    ],
  },

  'veo-3': {
    id: 'veo-3',
    displayName: 'Veo 3.1',
    category: 'video-gen',
    apiProvider: 'google',
    apiEndpoint: 'veo-3.1-generate-preview',
    envKeyName: ['GOOGLE_API_KEY', 'FAL_KEY'],
    executionPattern: 'async-poll',
    directKeyName: 'GOOGLE_API_KEY',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'image', label: 'First Frame', dataType: 'Image', required: false },
      { id: 'last_frame', label: 'Last Frame', dataType: 'Image', required: false },
      { id: 'video', label: 'Extend Video', dataType: 'Video', required: false },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
      { id: 'source_uri', label: 'Source URI', dataType: 'Video', required: false },
    ],
    params: [],
    sharedParams: [
      {
        key: 'aspectRatio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: '16:9',
        options: [
          { label: '16:9', value: '16:9' },
          { label: '9:16', value: '9:16' },
        ],
      },
      {
        key: 'duration',
        label: 'Duration',
        type: 'enum',
        required: false,
        default: '8',
        options: [
          { label: '4 seconds', value: '4', visibleWhen: { model: ['veo-3.1-generate-preview', 'veo-3.1-fast-generate-preview', 'veo-3.1-lite-generate-preview', 'veo-3.0-generate-001', 'veo-3.0-fast-generate-001'] } },
          { label: '5 seconds', value: '5', visibleWhen: { model: ['veo-2.0-generate-001'] } },
          { label: '6 seconds', value: '6' },
          { label: '8 seconds', value: '8' },
        ],
      },
      {
        key: 'resolution',
        label: 'Resolution',
        type: 'enum',
        required: false,
        default: '720p',
        visibleWhen: { model: ['veo-3.1-generate-preview', 'veo-3.1-fast-generate-preview', 'veo-3.1-lite-generate-preview', 'veo-3.0-generate-001', 'veo-3.0-fast-generate-001'] },
        options: [
          { label: '720p', value: '720p' },
          { label: '1080p', value: '1080p' },
          { label: '4K', value: '4k', visibleWhen: { model: ['veo-3.1-generate-preview', 'veo-3.1-fast-generate-preview', 'veo-3.0-generate-001', 'veo-3.0-fast-generate-001'] } },
        ],
      },
      {
        key: 'personGeneration',
        label: 'Person Generation',
        type: 'enum',
        required: false,
        default: 'allow_adult',
        options: [
          { label: 'Allow All', value: 'allow_all' },
          { label: 'Allow Adult', value: 'allow_adult' },
          { label: "Don't Allow", value: 'dont_allow' },
        ],
      },
    ],
    directParams: [
      {
        key: 'model',
        label: 'Model',
        type: 'enum',
        required: false,
        default: 'veo-3.1-generate-preview',
        options: [
          { label: 'Veo 3.1', value: 'veo-3.1-generate-preview' },
          { label: 'Veo 3.1 Fast', value: 'veo-3.1-fast-generate-preview' },
          { label: 'Veo 3.1 Lite', value: 'veo-3.1-lite-generate-preview' },
          { label: 'Veo 3', value: 'veo-3.0-generate-001' },
          { label: 'Veo 3 Fast', value: 'veo-3.0-fast-generate-001' },
          { label: 'Veo 2', value: 'veo-2.0-generate-001' },
        ],
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
        visibleWhen: { model: ['veo-3.1-generate-preview', 'veo-3.1-fast-generate-preview', 'veo-3.1-lite-generate-preview', 'veo-3.0-generate-001', 'veo-3.0-fast-generate-001'] },
      },
    ],
    falParams: [
      {
        key: 'negative_prompt',
        label: 'Negative Prompt',
        type: 'string',
        required: false,
        placeholder: 'What to avoid',
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
      {
        key: 'safety_tolerance',
        label: 'Safety Tolerance',
        type: 'enum',
        required: false,
        default: '4',
        options: [
          { label: '1 (Strict)', value: '1' },
          { label: '2', value: '2' },
          { label: '3', value: '3' },
          { label: '4', value: '4' },
          { label: '5', value: '5' },
          { label: '6 (Permissive)', value: '6' },
        ],
      },
    ],
  },

  'flux-schnell': {
    id: 'flux-schnell',
    displayName: 'FLUX Schnell',
    category: 'image-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/flux/schnell',
    envKeyName: 'FAL_KEY',
    executionPattern: 'sync',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'image_size',
        label: 'Image Size',
        type: 'enum',
        required: false,
        default: 'landscape_4_3',
        options: [
          { label: 'Square HD (1024×1024)', value: 'square_hd' },
          { label: 'Square (512×512)', value: 'square' },
          { label: 'Landscape 4:3', value: 'landscape_4_3' },
          { label: 'Landscape 16:9', value: 'landscape_16_9' },
          { label: 'Portrait 4:3', value: 'portrait_4_3' },
          { label: 'Portrait 16:9', value: 'portrait_16_9' },
        ],
      },
      {
        key: 'num_inference_steps',
        label: 'Steps',
        type: 'integer',
        required: false,
        default: 4,
        min: 1,
        max: 4,
      },
      {
        key: 'guidance_scale',
        label: 'Guidance Scale',
        type: 'float',
        required: false,
        default: 3.5,
        min: 1.0,
        max: 5.0,
      },
      {
        key: 'num_images',
        label: 'Count',
        type: 'integer',
        required: false,
        default: 1,
        min: 1,
        max: 4,
      },
      {
        key: 'output_format',
        label: 'Format',
        type: 'enum',
        required: false,
        default: 'jpeg',
        options: [
          { label: 'JPEG', value: 'jpeg' },
          { label: 'PNG', value: 'png' },
          { label: 'WebP', value: 'webp' },
        ],
      },
      {
        key: 'acceleration',
        label: 'Acceleration',
        type: 'enum',
        required: false,
        default: 'none',
        options: [
          { label: 'None', value: 'none' },
          { label: 'Regular', value: 'regular' },
          { label: 'High', value: 'high' },
        ],
      },
      {
        key: 'enable_safety_checker',
        label: 'Safety Checker',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        min: 0,
        max: 2147483647,
      },
    ],
  },

  'flux-fill-inpaint': {
    id: 'flux-fill-inpaint',
    displayName: 'FLUX Fill (Inpaint)',
    category: 'image-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/flux-pro/v1/fill',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'image', label: 'Base Image', dataType: 'Image', required: true },
      { id: 'mask', label: 'Mask (white = edit)', dataType: 'Image', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      { key: 'num_images', label: 'Count', type: 'integer', required: false, default: 1, min: 1, max: 4 },
      {
        key: 'output_format',
        label: 'Format',
        type: 'enum',
        required: false,
        default: 'jpeg',
        options: [
          { label: 'JPEG', value: 'jpeg' },
          { label: 'PNG', value: 'png' },
        ],
      },
      { key: 'enhance_prompt', label: 'Enhance Prompt', type: 'boolean', required: false, default: false },
      { key: 'seed', label: 'Seed', type: 'integer', required: false, placeholder: 'Random' },
    ],
  },

  'fast-sdxl': {
    id: 'fast-sdxl',
    displayName: 'Fast SDXL',
    category: 'image-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/fast-sdxl',
    envKeyName: 'FAL_KEY',
    executionPattern: 'sync',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'image_size',
        label: 'Image Size',
        type: 'enum',
        required: false,
        default: 'square_hd',
        options: [
          { label: 'Square HD', value: 'square_hd' },
          { label: 'Square', value: 'square' },
          { label: 'Landscape 4:3', value: 'landscape_4_3' },
          { label: 'Landscape 16:9', value: 'landscape_16_9' },
          { label: 'Portrait 4:3', value: 'portrait_4_3' },
          { label: 'Portrait 16:9', value: 'portrait_16_9' },
        ],
      },
      {
        key: 'num_images',
        label: 'Count',
        type: 'integer',
        required: false,
        default: 1,
        min: 1,
        max: 4,
      },
      {
        key: 'num_inference_steps',
        label: 'Steps',
        type: 'integer',
        required: false,
        default: 25,
        min: 1,
        max: 50,
      },
      {
        key: 'guidance_scale',
        label: 'Guidance Scale',
        type: 'float',
        required: false,
        default: 7.5,
        min: 1,
        max: 20,
        step: 0.5,
      },
      {
        key: 'negative_prompt',
        label: 'Negative Prompt',
        type: 'string',
        required: false,
        default: '',
        placeholder: 'What to avoid in the image...',
      },
      {
        key: 'expand_prompt',
        label: 'Expand Prompt',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'loras',
        label: 'LoRAs (JSON)',
        type: 'textarea',
        required: false,
        default: '',
        placeholder: '[{"path":"https://...safetensors","scale":1.0}]',
      },
      {
        key: 'embeddings',
        label: 'Embeddings (JSON)',
        type: 'textarea',
        required: false,
        default: '',
        placeholder: '[{"path":"https://...","tokens":["<s0>"]}]',
      },
      {
        key: 'format',
        label: 'Format',
        type: 'enum',
        required: false,
        default: 'jpeg',
        options: [
          { label: 'JPEG', value: 'jpeg' },
          { label: 'PNG', value: 'png' },
        ],
      },
      {
        key: 'enable_safety_checker',
        label: 'Safety Checker',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'safety_checker_version',
        label: 'Safety Checker Version',
        type: 'enum',
        required: false,
        default: 'v1',
        options: [
          { label: 'v1 (Default)', value: 'v1' },
          { label: 'v2 (ViT)', value: 'v2' },
        ],
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        min: 0,
        max: 4294967295,
      },
    ],
  },

  'wan-2-6-t2v': {
    id: 'wan-2-6-t2v',
    displayName: 'Wan 2.6 T2V',
    category: 'video-gen',
    apiProvider: 'fal',
    apiEndpoint: 'wan/v2.6/text-to-video',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'duration',
        label: 'Duration',
        type: 'enum',
        required: false,
        default: 5,
        options: [
          { label: '5 seconds', value: 5 },
          { label: '10 seconds', value: 10 },
          { label: '15 seconds', value: 15 },
        ],
      },
      {
        key: 'resolution',
        label: 'Resolution',
        type: 'enum',
        required: false,
        default: '720p',
        options: [
          { label: '720p', value: '720p' },
          { label: '1080p', value: '1080p' },
        ],
      },
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: '16:9',
        options: [
          { label: '16:9', value: '16:9' },
          { label: '9:16', value: '9:16' },
          { label: '1:1', value: '1:1' },
          { label: '4:3', value: '4:3' },
          { label: '3:4', value: '3:4' },
        ],
      },
      {
        key: 'negative_prompt',
        label: 'Negative Prompt',
        type: 'string',
        required: false,
        placeholder: 'What to avoid',
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
      {
        key: 'generate_audio',
        label: 'Generate Audio',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'enable_prompt_expansion',
        label: 'Prompt Expansion',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'multi_shots',
        label: 'Multi-Shot',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'enable_safety_checker',
        label: 'Safety Checker',
        type: 'boolean',
        required: false,
        default: true,
      },
    ],
  },

  'luma-ray2-t2v': {
    id: 'luma-ray2-t2v',
    displayName: 'Luma Ray 2',
    category: 'video-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/luma-dream-machine/ray-2',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: '16:9',
        options: [
          { label: '16:9', value: '16:9' },
          { label: '9:16', value: '9:16' },
          { label: '4:3', value: '4:3' },
          { label: '3:4', value: '3:4' },
          { label: '21:9', value: '21:9' },
          { label: '9:21', value: '9:21' },
        ],
      },
      {
        key: 'duration',
        label: 'Duration',
        type: 'enum',
        required: false,
        default: '5s',
        options: [
          { label: '5 seconds', value: '5s' },
          { label: '9 seconds', value: '9s' },
        ],
      },
      {
        key: 'loop',
        label: 'Seamless Loop',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'resolution',
        label: 'Resolution',
        type: 'enum',
        required: false,
        default: '540p',
        options: [
          { label: '540p', value: '540p' },
          { label: '720p', value: '720p' },
          { label: '1080p', value: '1080p' },
        ],
      },
    ],
  },

  'ltx-video-2': {
    id: 'ltx-video-2',
    displayName: 'LTX Video 2',
    category: 'video-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/ltx-2/image-to-video',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'duration',
        label: 'Duration',
        type: 'enum',
        required: false,
        default: '6',
        options: [
          { label: '6 seconds', value: '6' },
          { label: '8 seconds', value: '8' },
          { label: '10 seconds', value: '10' },
        ],
      },
      {
        key: 'resolution',
        label: 'Resolution',
        type: 'enum',
        required: false,
        default: '1080p',
        options: [
          { label: '1080p', value: '1080p' },
          { label: '1440p', value: '1440p' },
          { label: '2160p', value: '2160p' },
        ],
      },
      {
        key: 'fps',
        label: 'FPS',
        type: 'enum',
        required: false,
        default: '25',
        options: [
          { label: '25', value: '25' },
          { label: '50', value: '50' },
        ],
      },
      {
        key: 'generate_audio',
        label: 'Generate Audio',
        type: 'boolean',
        required: false,
        default: true,
      },
    ],
  },

  'meshy-text-to-3d': {
    id: 'meshy-text-to-3d',
    displayName: 'Meshy 6 Text-to-3D',
    category: '3d-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/meshy/v6/text-to-3d',
    envKeyName: ['MESHY_API_KEY', 'FAL_KEY'],
    executionPattern: 'async-poll',
    directKeyName: 'MESHY_API_KEY',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'mesh', label: 'Mesh', dataType: 'Mesh', required: false },
    ],
    params: [],
    sharedParams: [
      {
        key: 'mode',
        label: 'Mode',
        type: 'enum',
        required: false,
        default: 'full',
        options: [
          { label: 'Preview', value: 'preview' },
          { label: 'Full', value: 'full' },
        ],
      },
      {
        key: 'model_type',
        label: 'Mesh Type',
        type: 'enum',
        required: false,
        default: 'standard',
        options: [
          { label: 'Standard', value: 'standard' },
          { label: 'Low Poly', value: 'lowpoly' },
        ],
      },
      {
        key: 'should_remesh',
        label: 'Remesh',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'topology',
        label: 'Topology',
        type: 'enum',
        required: false,
        default: 'triangle',
        options: [
          { label: 'Triangle', value: 'triangle' },
          { label: 'Quad', value: 'quad' },
        ],
      },
      {
        key: 'target_polycount',
        label: 'Polycount',
        type: 'integer',
        required: false,
        default: 30000,
        min: 100,
        max: 300000,
      },
      {
        key: 'symmetry_mode',
        label: 'Symmetry',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Off', value: 'off' },
          { label: 'Auto', value: 'auto' },
          { label: 'On', value: 'on' },
        ],
      },
      {
        key: 'enable_pbr',
        label: 'PBR Materials',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'pose_mode',
        label: 'Pose Mode',
        type: 'enum',
        required: false,
        default: '',
        options: [
          { label: 'None', value: '' },
          { label: 'A-Pose', value: 'a-pose' },
          { label: 'T-Pose', value: 't-pose' },
        ],
      },
    ],
    directParams: [
      {
        key: 'ai_model',
        label: 'AI Model',
        type: 'enum',
        required: false,
        default: 'latest',
        options: [
          { label: 'Latest (Meshy 6)', value: 'latest' },
          { label: 'Meshy 6', value: 'meshy-6' },
          { label: 'Meshy 5', value: 'meshy-5' },
        ],
      },
      {
        key: 'hd_texture',
        label: 'HD Texture (4K)',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'remove_lighting',
        label: 'Remove Lighting',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'target_formats',
        label: 'Output Formats',
        type: 'string',
        required: false,
        default: 'glb',
        placeholder: 'glb,fbx,obj,usdz',
      },
    ],
    falParams: [
      {
        key: 'texture_prompt',
        label: 'Texture Prompt',
        type: 'string',
        required: false,
        placeholder: 'Guide the texturing process',
      },
      {
        key: 'enable_prompt_expansion',
        label: 'Enhance Prompt',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'enable_safety_checker',
        label: 'Safety Checker',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
  },

  'meshy-image-to-3d': {
    id: 'meshy-image-to-3d',
    displayName: 'Meshy 6 Image-to-3D',
    category: '3d-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/meshy/v6/image-to-3d',
    envKeyName: ['MESHY_API_KEY', 'FAL_KEY'],
    executionPattern: 'async-poll',
    directKeyName: 'MESHY_API_KEY',
    inputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
    ],
    outputPorts: [
      { id: 'mesh', label: 'Mesh', dataType: 'Mesh', required: false },
    ],
    params: [],
    sharedParams: [
      {
        key: 'topology',
        label: 'Topology',
        type: 'enum',
        required: false,
        default: 'triangle',
        options: [
          { label: 'Triangle', value: 'triangle' },
          { label: 'Quad', value: 'quad' },
        ],
      },
      {
        key: 'target_polycount',
        label: 'Polycount',
        type: 'integer',
        required: false,
        default: 30000,
        min: 100,
        max: 300000,
      },
      {
        key: 'symmetry_mode',
        label: 'Symmetry',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Off', value: 'off' },
          { label: 'Auto', value: 'auto' },
          { label: 'On', value: 'on' },
        ],
      },
      {
        key: 'should_remesh',
        label: 'Remesh',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'should_texture',
        label: 'Texture',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'enable_pbr',
        label: 'PBR Materials',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'pose_mode',
        label: 'Pose Mode',
        type: 'enum',
        required: false,
        default: '',
        options: [
          { label: 'None', value: '' },
          { label: 'A-Pose', value: 'a-pose' },
          { label: 'T-Pose', value: 't-pose' },
        ],
      },
    ],
    directParams: [
      {
        key: 'ai_model',
        label: 'AI Model',
        type: 'enum',
        required: false,
        default: 'latest',
        options: [
          { label: 'Latest (Meshy 6)', value: 'latest' },
          { label: 'Meshy 6', value: 'meshy-6' },
          { label: 'Meshy 5', value: 'meshy-5' },
        ],
      },
      {
        key: 'model_type',
        label: 'Mesh Type',
        type: 'enum',
        required: false,
        default: 'standard',
        options: [
          { label: 'Standard', value: 'standard' },
          { label: 'Low Poly', value: 'lowpoly' },
        ],
      },
      {
        key: 'hd_texture',
        label: 'HD Texture (4K)',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'image_enhancement',
        label: 'Image Enhancement',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'remove_lighting',
        label: 'Remove Lighting',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'target_formats',
        label: 'Output Formats',
        type: 'string',
        required: false,
        default: 'glb',
        placeholder: 'glb,fbx,obj,usdz',
      },
    ],
    falParams: [
      {
        key: 'texture_prompt',
        label: 'Texture Prompt',
        type: 'string',
        required: false,
        placeholder: 'Guide the texturing process',
      },
      {
        key: 'enable_safety_checker',
        label: 'Safety Checker',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
  },

  'meshy-multi-image-to-3d': {
    id: 'meshy-multi-image-to-3d',
    displayName: 'Meshy Multi-Image-to-3D',
    category: '3d-gen',
    apiProvider: 'meshy',
    apiEndpoint: '/openapi/v1/multi-image-to-3d',
    envKeyName: 'MESHY_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'images', label: 'Images (1-4)', dataType: 'Image', required: true, multiple: true },
    ],
    outputPorts: [
      { id: 'mesh', label: 'Mesh', dataType: 'Mesh', required: false },
    ],
    params: [
      {
        key: 'ai_model',
        label: 'AI Model',
        type: 'enum',
        required: false,
        default: 'latest',
        options: [
          { label: 'Latest (Meshy 6)', value: 'latest' },
          { label: 'Meshy 6', value: 'meshy-6' },
          { label: 'Meshy 5', value: 'meshy-5' },
        ],
      },
      {
        key: 'should_remesh',
        label: 'Remesh',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'topology',
        label: 'Topology',
        type: 'enum',
        required: false,
        default: 'triangle',
        options: [
          { label: 'Triangle', value: 'triangle' },
          { label: 'Quad', value: 'quad' },
        ],
      },
      {
        key: 'target_polycount',
        label: 'Polycount',
        type: 'integer',
        required: false,
        default: 30000,
        min: 100,
        max: 300000,
      },
      {
        key: 'symmetry_mode',
        label: 'Symmetry (deprecated)',
        type: 'enum',
        required: false,
        default: 'auto',
        hidden: true,
        options: [
          { label: 'Off', value: 'off' },
          { label: 'Auto', value: 'auto' },
          { label: 'On', value: 'on' },
        ],
      },
      {
        key: 'should_texture',
        label: 'Texture',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'enable_pbr',
        label: 'PBR Materials',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'pose_mode',
        label: 'Pose Mode',
        type: 'enum',
        required: false,
        default: '',
        options: [
          { label: 'None', value: '' },
          { label: 'A-Pose', value: 'a-pose' },
          { label: 'T-Pose', value: 't-pose' },
        ],
      },
      {
        key: 'hd_texture',
        label: 'HD Texture (4K)',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'image_enhancement',
        label: 'Image Enhancement',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'remove_lighting',
        label: 'Remove Lighting',
        type: 'boolean',
        required: false,
        default: true,
      },
    ],
  },

  'meshy-retexture': {
    id: 'meshy-retexture',
    displayName: 'Meshy Retexture',
    category: '3d-gen',
    apiProvider: 'meshy',
    apiEndpoint: '/openapi/v1/retexture',
    envKeyName: 'MESHY_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'model_url', label: 'Model URL', dataType: 'Text', required: true },
      { id: 'prompt', label: 'Style Prompt', dataType: 'Text', required: false },
    ],
    outputPorts: [
      { id: 'mesh', label: 'Mesh', dataType: 'Mesh', required: false },
    ],
    params: [
      {
        key: 'ai_model',
        label: 'AI Model',
        type: 'enum',
        required: false,
        default: 'latest',
        options: [
          { label: 'Latest (Meshy 6)', value: 'latest' },
          { label: 'Meshy 6', value: 'meshy-6' },
          { label: 'Meshy 5', value: 'meshy-5' },
        ],
      },
      {
        key: 'enable_original_uv',
        label: 'Keep Original UV',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'enable_pbr',
        label: 'PBR Materials',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'remove_lighting',
        label: 'Remove Lighting',
        type: 'boolean',
        required: false,
        default: true,
      },
    ],
  },

  'meshy-rigging': {
    id: 'meshy-rigging',
    displayName: 'Meshy Auto-Rig',
    category: '3d-gen',
    apiProvider: 'meshy',
    apiEndpoint: '/openapi/v1/rigging',
    envKeyName: 'MESHY_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'model_url', label: 'Model URL', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'mesh', label: 'Rigged Mesh', dataType: 'Mesh', required: false },
      { id: 'task_id', label: 'Rig Task ID', dataType: 'Text', required: false },
    ],
    params: [
      {
        key: 'height_meters',
        label: 'Height (meters)',
        type: 'float',
        required: false,
        default: 1.7,
        min: 0.1,
        max: 5.0,
        step: 0.1,
      },
    ],
  },

  'meshy-animate': {
    id: 'meshy-animate',
    displayName: 'Meshy Animate',
    category: '3d-gen',
    apiProvider: 'meshy',
    apiEndpoint: '/openapi/v1/animations',
    envKeyName: 'MESHY_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'rig_task_id', label: 'Rig Task ID', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'mesh', label: 'Animated Mesh', dataType: 'Mesh', required: false },
    ],
    params: [
      {
        key: 'action_id',
        label: 'Animation',
        type: 'enum',
        required: true,
        default: '92',
        options: [
          { label: 'Idle', value: '1' },
          { label: 'Walking', value: '2' },
          { label: 'Running', value: '3' },
          { label: 'Jumping', value: '7' },
          { label: 'Dancing', value: '10' },
          { label: 'Waving', value: '15' },
          { label: 'Sitting', value: '20' },
          { label: 'Clapping', value: '25' },
          { label: 'Punching', value: '30' },
          { label: 'Kicking', value: '35' },
          { label: 'Sword Swing', value: '92' },
        ],
      },
      {
        key: 'fps',
        label: 'Output FPS',
        type: 'enum',
        required: false,
        default: '',
        options: [
          { label: 'Default (30)', value: '' },
          { label: '24 fps', value: '24' },
          { label: '25 fps', value: '25' },
          { label: '30 fps', value: '30' },
          { label: '60 fps', value: '60' },
        ],
      },
    ],
  },

  'meshy-remesh': {
    id: 'meshy-remesh',
    displayName: 'Meshy Remesh',
    category: '3d-gen',
    apiProvider: 'meshy',
    apiEndpoint: '/openapi/v1/remesh',
    envKeyName: 'MESHY_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'model_url', label: 'Model URL', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'mesh', label: 'Mesh', dataType: 'Mesh', required: false },
    ],
    params: [
      {
        key: 'topology',
        label: 'Topology',
        type: 'enum',
        required: false,
        default: 'triangle',
        options: [
          { label: 'Triangle', value: 'triangle' },
          { label: 'Quad', value: 'quad' },
        ],
      },
      {
        key: 'target_polycount',
        label: 'Polycount',
        type: 'integer',
        required: false,
        default: 30000,
        min: 100,
        max: 300000,
      },
      {
        key: 'target_formats',
        label: 'Output Formats',
        type: 'string',
        required: false,
        default: 'glb',
        placeholder: 'glb,fbx,obj,usdz,blend,stl',
      },
      {
        key: 'resize_height',
        label: 'Resize Height (m)',
        type: 'float',
        required: false,
        default: 0,
        min: 0,
        max: 100,
        step: 0.1,
        placeholder: '0 = no resize',
      },
      {
        key: 'convert_format_only',
        label: 'Convert Format Only',
        type: 'boolean',
        required: false,
        default: false,
      },
    ],
  },

  'meshy-text-to-image': {
    id: 'meshy-text-to-image',
    displayName: 'Meshy Text-to-Image',
    category: 'image-gen',
    apiProvider: 'meshy',
    apiEndpoint: '/openapi/v1/text-to-image',
    envKeyName: 'MESHY_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'ai_model',
        label: 'Model',
        type: 'enum',
        required: false,
        default: 'nano-banana',
        options: [
          { label: 'Nano Banana', value: 'nano-banana' },
          { label: 'Nano Banana 2', value: 'nano-banana-2' },
          { label: 'Nano Banana Pro', value: 'nano-banana-pro' },
          { label: 'GPT Image 2', value: 'gpt-image-2' },
        ],
      },
      {
        key: 'generate_multi_view',
        label: 'Multi-View',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: '1:1',
        visibleWhen: { generate_multi_view: [false] },
        options: [
          { label: '1:1', value: '1:1' },
          { label: '16:9', value: '16:9' },
          { label: '9:16', value: '9:16' },
          { label: '4:3', value: '4:3' },
          { label: '3:4', value: '3:4' },
        ],
      },
      {
        key: 'pose_mode',
        label: 'Pose Mode',
        type: 'enum',
        required: false,
        default: '',
        options: [
          { label: 'None', value: '' },
          { label: 'A-Pose', value: 'a-pose' },
          { label: 'T-Pose', value: 't-pose' },
        ],
      },
    ],
  },

  'meshy-image-to-image': {
    id: 'meshy-image-to-image',
    displayName: 'Meshy Image-to-Image',
    category: 'image-gen',
    apiProvider: 'meshy',
    apiEndpoint: '/openapi/v1/image-to-image',
    envKeyName: 'MESHY_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'images', label: 'Reference Images', dataType: 'Image', required: true, multiple: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'ai_model',
        label: 'Model',
        type: 'enum',
        required: false,
        default: 'nano-banana',
        options: [
          { label: 'Nano Banana', value: 'nano-banana' },
          { label: 'Nano Banana 2', value: 'nano-banana-2' },
          { label: 'Nano Banana Pro', value: 'nano-banana-pro' },
          { label: 'GPT Image 2', value: 'gpt-image-2' },
        ],
      },
      {
        key: 'generate_multi_view',
        label: 'Multi-View',
        type: 'boolean',
        required: false,
        default: false,
      },
    ],
  },

  'meshy-3d-print': {
    id: 'meshy-3d-print',
    displayName: 'Meshy 3D Print',
    category: '3d-gen',
    apiProvider: 'meshy',
    apiEndpoint: '/openapi/v1/print/multi-color',
    envKeyName: 'MESHY_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'task_id', label: 'Task ID', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'mesh', label: 'Print File', dataType: 'Mesh', required: false },
    ],
    params: [
      {
        key: 'max_colors',
        label: 'Max Colors',
        type: 'integer',
        required: false,
        default: 4,
        min: 1,
        max: 16,
      },
      {
        key: 'max_depth',
        label: 'Color Depth',
        type: 'integer',
        required: false,
        default: 4,
        min: 3,
        max: 6,
      },
    ],
  },

  'hunyuan3d-text-to-3d': {
    id: 'hunyuan3d-text-to-3d',
    displayName: 'Hunyuan3D V3 Text-to-3D',
    category: '3d-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/hunyuan3d-v3/text-to-3d',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'mesh', label: 'Mesh', dataType: 'Mesh', required: false },
    ],
    params: [
      {
        key: 'generate_type',
        label: 'Quality',
        type: 'enum',
        required: false,
        default: 'Normal',
        options: [
          { label: 'Normal', value: 'Normal' },
          { label: 'Low Poly', value: 'LowPoly' },
          { label: 'Geometry Only', value: 'Geometry' },
        ],
      },
      {
        key: 'face_count',
        label: 'Face Count',
        type: 'integer',
        required: false,
        default: 500000,
        min: 40000,
        max: 1500000,
      },
      {
        key: 'enable_pbr',
        label: 'PBR Materials',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'polygon_type',
        label: 'Polygon Type',
        type: 'enum',
        required: false,
        default: 'triangle',
        options: [
          { label: 'Triangle', value: 'triangle' },
          { label: 'Quadrilateral', value: 'quadrilateral' },
        ],
      },
    ],
  },

  'hunyuan3d-image-to-3d': {
    id: 'hunyuan3d-image-to-3d',
    displayName: 'Hunyuan3D V3 Image-to-3D',
    category: '3d-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/hunyuan3d-v3/image-to-3d',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'front_image', label: 'Front Image', dataType: 'Image', required: true },
      { id: 'back_image', label: 'Back Image', dataType: 'Image', required: false },
      { id: 'left_image', label: 'Left Image', dataType: 'Image', required: false },
      { id: 'right_image', label: 'Right Image', dataType: 'Image', required: false },
    ],
    outputPorts: [
      { id: 'mesh', label: 'Mesh', dataType: 'Mesh', required: false },
    ],
    params: [
      {
        key: 'generate_type',
        label: 'Quality',
        type: 'enum',
        required: false,
        default: 'Normal',
        options: [
          { label: 'Normal', value: 'Normal' },
          { label: 'Low Poly', value: 'LowPoly' },
          { label: 'Geometry Only', value: 'Geometry' },
        ],
      },
      {
        key: 'face_count',
        label: 'Face Count',
        type: 'integer',
        required: false,
        default: 500000,
        min: 40000,
        max: 1500000,
      },
      {
        key: 'enable_pbr',
        label: 'PBR Materials',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'polygon_type',
        label: 'Polygon Type',
        type: 'enum',
        required: false,
        default: 'triangle',
        options: [
          { label: 'Triangle', value: 'triangle' },
          { label: 'Quadrilateral', value: 'quadrilateral' },
        ],
      },
    ],
  },

  'gpt-image-1-edit': {
    id: 'gpt-image-1-edit',
    displayName: 'GPT Image 1 Edit',
    category: 'image-gen',
    apiProvider: 'openai',
    apiEndpoint: '/v1/images/edits',
    envKeyName: 'OPENAI_API_KEY',
    executionPattern: 'sync',
    inputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'mask', label: 'Mask', dataType: 'Mask', required: false },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'enum',
        required: true,
        default: 'gpt-image-1',
        options: [
          { label: 'GPT Image 1', value: 'gpt-image-1' },
          { label: 'GPT Image 1.5', value: 'gpt-image-1.5' },
          { label: 'GPT Image 1 Mini', value: 'gpt-image-1-mini' },
        ],
      },
      {
        key: 'n',
        label: 'Count',
        type: 'integer',
        required: false,
        default: 1,
        min: 1,
        max: 10,
      },
      {
        key: 'size',
        label: 'Size',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: '1024×1024', value: '1024x1024' },
          { label: '1536×1024', value: '1536x1024' },
          { label: '1024×1536', value: '1024x1536' },
        ],
      },
      {
        key: 'quality',
        label: 'Quality',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: 'Low', value: 'low' },
          { label: 'Medium', value: 'medium' },
          { label: 'High', value: 'high' },
        ],
      },
      {
        key: 'output_format',
        label: 'Format',
        type: 'enum',
        required: false,
        default: 'png',
        options: [
          { label: 'PNG', value: 'png' },
          { label: 'JPEG', value: 'jpeg' },
          { label: 'WebP', value: 'webp' },
        ],
      },
      {
        key: 'background',
        label: 'Background',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: 'Transparent', value: 'transparent' },
          { label: 'Opaque', value: 'opaque' },
        ],
      },
    ],
  },

  'remove-background': {
    id: 'remove-background',
    displayName: 'Remove Background',
    category: 'transform',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/imageutils/rembg',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'crop_to_bbox',
        label: 'Crop to Subject',
        type: 'boolean',
        required: false,
        default: false,
      },
    ],
  },

  'recraft-v4-raster': {
    id: 'recraft-v4-raster',
    displayName: 'Recraft V4',
    category: 'image-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/recraft/v4/text-to-image',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'image_size',
        label: 'Size',
        type: 'enum',
        required: false,
        default: 'square_hd',
        options: [
          { label: 'Square HD', value: 'square_hd' },
          { label: 'Square', value: 'square' },
          { label: 'Portrait 4:3', value: 'portrait_4_3' },
          { label: 'Portrait 16:9', value: 'portrait_16_9' },
          { label: 'Landscape 4:3', value: 'landscape_4_3' },
          { label: 'Landscape 16:9', value: 'landscape_16_9' },
        ],
      },
      {
        key: 'style_id',
        label: 'Style ID',
        type: 'string',
        required: false,
        placeholder: 'Custom style UUID (Recraft style reference)',
      },
      {
        key: 'colors',
        label: 'Color Palette',
        type: 'string',
        required: false,
        placeholder: '[{"r":255,"g":0,"b":0},{"r":0,"g":255,"b":0}]',
      },
      {
        key: 'background_color',
        label: 'Background Color',
        type: 'string',
        required: false,
        placeholder: '{"r":255,"g":255,"b":255}',
      },
      {
        key: 'enable_safety_checker',
        label: 'Safety Checker',
        type: 'boolean',
        required: false,
        default: true,
      },
    ],
  },

  'recraft-v4-svg': {
    id: 'recraft-v4-svg',
    displayName: 'Recraft V4 SVG',
    category: 'image-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/recraft/v4/text-to-vector',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'svg', label: 'SVG', dataType: 'SVG', required: false },
    ],
    params: [
      {
        key: 'image_size',
        label: 'Size',
        type: 'enum',
        required: false,
        default: 'square_hd',
        options: [
          { label: 'Square HD', value: 'square_hd' },
          { label: 'Square', value: 'square' },
          { label: 'Portrait 4:3', value: 'portrait_4_3' },
          { label: 'Portrait 16:9', value: 'portrait_16_9' },
          { label: 'Landscape 4:3', value: 'landscape_4_3' },
          { label: 'Landscape 16:9', value: 'landscape_16_9' },
        ],
      },
      {
        key: 'style_id',
        label: 'Style ID',
        type: 'string',
        required: false,
        placeholder: 'Custom style UUID (Recraft style reference)',
      },
      {
        key: 'colors',
        label: 'Color Palette',
        type: 'string',
        required: false,
        placeholder: '[{"r":255,"g":0,"b":0},{"r":0,"g":255,"b":0}]',
      },
      {
        key: 'background_color',
        label: 'Background Color',
        type: 'string',
        required: false,
        placeholder: '{"r":255,"g":255,"b":255}',
      },
      {
        key: 'enable_safety_checker',
        label: 'Safety Checker',
        type: 'boolean',
        required: false,
        default: true,
      },
    ],
  },

  'quiver-arrow-generate': {
    id: 'quiver-arrow-generate',
    displayName: 'Quiver Arrow Generate',
    category: 'image-gen',
    apiProvider: 'quiver',
    apiEndpoint: '/v1/svgs/generations',
    envKeyName: 'QUIVER_API_KEY',
    executionPattern: 'stream',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      // maxConnections:16 is the arrow-1.1-max ceiling; arrow-1 and arrow-1.1 only allow 4 refs at runtime — the backend returns 400 if exceeded.
      { id: 'references', label: 'References', dataType: 'Image', required: false, multiple: true, maxConnections: 16 },
    ],
    outputPorts: [
      { id: 'svg', label: 'SVG', dataType: 'SVG', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'enum',
        required: false,
        default: 'arrow-1.1',
        options: [
          { label: 'Arrow 1.1 (20 credits)', value: 'arrow-1.1' },
          { label: 'Arrow 1.1 max (25 credits)', value: 'arrow-1.1-max' },
          { label: 'Arrow 1 (30 credits, legacy)', value: 'arrow-1' },
        ],
      },
      { key: 'n', label: 'Outputs', type: 'integer', required: false, default: 1, min: 1, max: 16 },
      {
        key: 'instructions',
        label: 'Instructions',
        type: 'textarea',
        required: false,
        placeholder: 'Optional style/formatting guidance (e.g. "thin uniform stroke, no fill")',
      },
      { key: 'temperature', label: 'Temperature', type: 'float', required: false, default: 1.0, min: 0, max: 2, step: 0.1 },
      { key: 'top_p', label: 'Top P', type: 'float', required: false, default: 1.0, min: 0, max: 1, step: 0.05 },
      { key: 'presence_penalty', label: 'Presence Penalty', type: 'float', required: false, default: 0.0, min: -2, max: 2, step: 0.1 },
      { key: 'max_output_tokens', label: 'Max Output Tokens', type: 'integer', required: false, default: 16384, min: 1, max: 131072 },
    ],
  },

  'quiver-arrow-vectorize': {
    id: 'quiver-arrow-vectorize',
    displayName: 'Quiver Arrow Vectorize',
    category: 'image-gen',
    apiProvider: 'quiver',
    apiEndpoint: '/v1/svgs/vectorizations',
    envKeyName: 'QUIVER_API_KEY',
    executionPattern: 'stream',
    inputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
    ],
    outputPorts: [
      { id: 'svg', label: 'SVG', dataType: 'SVG', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'enum',
        required: false,
        default: 'arrow-1.1',
        options: [
          { label: 'Arrow 1.1 (15 credits)', value: 'arrow-1.1' },
          { label: 'Arrow 1.1 max (20 credits)', value: 'arrow-1.1-max' },
          { label: 'Arrow 1 (30 credits, legacy)', value: 'arrow-1' },
        ],
      },
      { key: 'auto_crop', label: 'Auto-crop to subject', type: 'boolean', required: false, default: false },
      { key: 'target_size', label: 'Target Size (px)', type: 'integer', required: false, default: 1024, min: 128, max: 4096 },
      { key: 'temperature', label: 'Temperature', type: 'float', required: false, default: 1.0, min: 0, max: 2, step: 0.1 },
      { key: 'top_p', label: 'Top P', type: 'float', required: false, default: 1.0, min: 0, max: 1, step: 0.05 },
      { key: 'presence_penalty', label: 'Presence Penalty', type: 'float', required: false, default: 0.0, min: -2, max: 2, step: 0.1 },
      { key: 'max_output_tokens', label: 'Max Output Tokens', type: 'integer', required: false, default: 16384, min: 1, max: 131072 },
    ],
  },

  'minimax-t2v': {
    id: 'minimax-t2v',
    displayName: 'MiniMax T2V',
    category: 'video-gen',
    apiProvider: 'minimax',
    apiEndpoint: 'https://api.minimaxi.com/v1/video_generation',
    envKeyName: 'MINIMAX_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'enum',
        required: false,
        default: 'MiniMax-Hailuo-2.3',
        options: [
          { label: 'Hailuo 2.3', value: 'MiniMax-Hailuo-2.3' },
          { label: 'Hailuo 2.3 Fast', value: 'MiniMax-Hailuo-2.3-Fast' },
          { label: 'Hailuo 02 (legacy)', value: 'MiniMax-Hailuo-02' },
        ],
      },
      {
        key: 'duration',
        label: 'Duration',
        type: 'enum',
        required: false,
        default: 6,
        options: [
          { label: '6 seconds', value: 6 },
          { label: '10 seconds', value: 10 },
        ],
      },
      {
        key: 'resolution',
        label: 'Resolution',
        type: 'enum',
        required: false,
        default: '768P',
        options: [
          { label: '768P', value: '768P' },
          { label: '1080P', value: '1080P' },
        ],
      },
    ],
  },

  'minimax-i2v': {
    id: 'minimax-i2v',
    displayName: 'MiniMax I2V',
    category: 'video-gen',
    apiProvider: 'minimax',
    apiEndpoint: 'https://api.minimaxi.com/v1/video_generation',
    envKeyName: 'MINIMAX_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'first_frame_image', label: 'First Frame', dataType: 'Image', required: true },
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'enum',
        required: false,
        default: 'MiniMax-Hailuo-2.3',
        options: [
          { label: 'Hailuo 2.3', value: 'MiniMax-Hailuo-2.3' },
          { label: 'Hailuo 2.3 Fast', value: 'MiniMax-Hailuo-2.3-Fast' },
          { label: 'Hailuo 02 (legacy)', value: 'MiniMax-Hailuo-02' },
        ],
      },
      {
        key: 'duration',
        label: 'Duration',
        type: 'enum',
        required: false,
        default: 6,
        options: [
          { label: '6 seconds', value: 6 },
          { label: '10 seconds', value: 10 },
        ],
      },
      {
        key: 'resolution',
        label: 'Resolution',
        type: 'enum',
        required: false,
        default: '768P',
        options: [
          { label: '768P', value: '768P' },
          { label: '1080P', value: '1080P' },
        ],
      },
    ],
  },

  'minimax-s2v': {
    id: 'minimax-s2v',
    displayName: 'MiniMax S2V',
    category: 'video-gen',
    apiProvider: 'minimax',
    apiEndpoint: 'https://api.minimaxi.com/v1/video_generation',
    envKeyName: 'MINIMAX_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'subject_reference', label: 'Character Image', dataType: 'Image', required: true },
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'enum',
        required: false,
        default: 'S2V-01',
        options: [
          { label: 'S2V-01', value: 'S2V-01' },
        ],
      },
    ],
  },

  'kling-v3': {
    id: 'kling-v3',
    displayName: 'Kling V3',
    category: 'video-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/kling-video/v3/standard/text-to-video',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'image', label: 'Start Image', dataType: 'Image', required: false },
      { id: 'end_image', label: 'End Image', dataType: 'Image', required: false },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'duration',
        label: 'Duration',
        type: 'enum',
        required: false,
        default: '5',
        options: [
          { label: '3 seconds', value: '3' },
          { label: '5 seconds', value: '5' },
          { label: '10 seconds', value: '10' },
          { label: '15 seconds', value: '15' },
        ],
      },
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: '16:9',
        options: [
          { label: '16:9', value: '16:9' },
          { label: '9:16', value: '9:16' },
          { label: '1:1', value: '1:1' },
        ],
      },
      {
        key: 'negative_prompt',
        label: 'Negative Prompt',
        type: 'string',
        required: false,
        default: 'blur, distort, and low quality',
      },
      {
        key: 'shot_type',
        label: 'Shot Type',
        type: 'enum',
        required: false,
        default: 'customize',
        options: [
          { label: 'Customize', value: 'customize' },
          { label: 'Intelligent (auto)', value: 'intelligent' },
        ],
      },
      {
        key: 'multi_prompt',
        label: 'Multi-Shot (JSON)',
        type: 'textarea',
        required: false,
        default: '',
        placeholder: '[{"prompt":"shot 1","duration":3},{"prompt":"shot 2","duration":4}]',
      },
      {
        key: 'generate_audio',
        label: 'Generate Audio',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'cfg_scale',
        label: 'CFG Scale',
        type: 'float',
        required: false,
        default: 0.5,
        min: 0,
        max: 1,
        step: 0.1,
      },
    ],
  },

  'luma-ray2-i2v': {
    id: 'luma-ray2-i2v',
    displayName: 'Luma Ray 2 I2V',
    category: 'video-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/luma-dream-machine/ray-2/image-to-video',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
      { id: 'end_image', label: 'End Image', dataType: 'Image', required: false },
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: false },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: '16:9',
        options: [
          { label: '16:9', value: '16:9' },
          { label: '9:16', value: '9:16' },
          { label: '4:3', value: '4:3' },
          { label: '3:4', value: '3:4' },
          { label: '21:9', value: '21:9' },
          { label: '9:21', value: '9:21' },
        ],
      },
      {
        key: 'resolution',
        label: 'Resolution',
        type: 'enum',
        required: false,
        default: '540p',
        options: [
          { label: '540p', value: '540p' },
          { label: '720p (2x cost)', value: '720p' },
          { label: '1080p (4x cost)', value: '1080p' },
        ],
      },
      {
        key: 'duration',
        label: 'Duration',
        type: 'enum',
        required: false,
        default: '5s',
        options: [
          { label: '5 seconds', value: '5s' },
          { label: '9 seconds', value: '9s' },
        ],
      },
      {
        key: 'loop',
        label: 'Seamless Loop',
        type: 'boolean',
        required: false,
        default: false,
      },
    ],
  },

  'wan-2-6-i2v': {
    id: 'wan-2-6-i2v',
    displayName: 'Wan 2.6 I2V',
    category: 'video-gen',
    apiProvider: 'fal',
    apiEndpoint: 'wan/v2.6/image-to-video',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'duration',
        label: 'Duration',
        type: 'enum',
        required: false,
        default: 5,
        options: [
          { label: '5 seconds', value: 5 },
          { label: '10 seconds', value: 10 },
          { label: '15 seconds', value: 15 },
        ],
      },
      {
        key: 'resolution',
        label: 'Resolution',
        type: 'enum',
        required: false,
        default: '720p',
        options: [
          { label: '720p', value: '720p' },
          { label: '1080p', value: '1080p' },
        ],
      },
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: '16:9',
        options: [
          { label: '16:9', value: '16:9' },
          { label: '9:16', value: '9:16' },
          { label: '1:1', value: '1:1' },
          { label: '4:3', value: '4:3' },
          { label: '3:4', value: '3:4' },
        ],
      },
      {
        key: 'negative_prompt',
        label: 'Negative Prompt',
        type: 'string',
        required: false,
        placeholder: 'What to avoid',
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
      {
        key: 'generate_audio',
        label: 'Generate Audio',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'enable_prompt_expansion',
        label: 'Prompt Expansion',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'multi_shots',
        label: 'Multi-Shot',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'enable_safety_checker',
        label: 'Safety Checker',
        type: 'boolean',
        required: false,
        default: true,
      },
    ],
  },
  'video-input': {
    id: 'video-input',
    displayName: 'Video Input',
    category: 'utility',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    inputPorts: [],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'filePath',
        label: 'File',
        type: 'file',
        required: true,
        default: '',
      },
    ],
  },
  'audio-input': {
    id: 'audio-input',
    displayName: 'Audio Input',
    category: 'utility',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    inputPorts: [],
    outputPorts: [
      { id: 'audio', label: 'Audio', dataType: 'Audio', required: false },
    ],
    params: [
      {
        key: 'filePath',
        label: 'File',
        type: 'file',
        required: true,
        default: '',
      },
    ],
  },
  'sticky-note': {
    id: 'sticky-note',
    displayName: 'Sticky Note',
    category: 'utility',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    inputPorts: [],
    outputPorts: [],
    params: [
      {
        key: 'content',
        label: 'Note',
        type: 'textarea',
        required: false,
        default: '',
        placeholder: 'Add a note...',
      },
      {
        key: 'color',
        label: 'Color',
        type: 'enum',
        required: false,
        default: 'yellow',
        options: [
          { label: 'Yellow', value: 'yellow' },
          { label: 'Blue', value: 'blue' },
          { label: 'Green', value: 'green' },
          { label: 'Pink', value: 'pink' },
          { label: 'Grey', value: 'grey' },
        ],
      },
    ],
  },
  'luma-ray2-flash-modify': {
    id: 'luma-ray2-flash-modify',
    displayName: 'Luma Ray 2 Flash Modify',
    category: 'video-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/luma-dream-machine/ray-2-flash/modify',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: true },
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: false },
      { id: 'image', label: 'Reference Image', dataType: 'Image', required: false },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'mode',
        label: 'Modification Mode',
        type: 'enum',
        required: false,
        default: 'flex_1',
        options: [
          { label: 'Adhere 1 (least)', value: 'adhere_1' },
          { label: 'Adhere 2', value: 'adhere_2' },
          { label: 'Adhere 3', value: 'adhere_3' },
          { label: 'Flex 1', value: 'flex_1' },
          { label: 'Flex 2', value: 'flex_2' },
          { label: 'Flex 3', value: 'flex_3' },
          { label: 'Reimagine 1', value: 'reimagine_1' },
          { label: 'Reimagine 2', value: 'reimagine_2' },
          { label: 'Reimagine 3 (most)', value: 'reimagine_3' },
        ],
      },
    ],
  },
  'wan-2-6-r2v': {
    id: 'wan-2-6-r2v',
    displayName: 'Wan 2.6 R2V',
    category: 'video-gen',
    apiProvider: 'fal',
    apiEndpoint: 'wan/v2.6/reference-to-video',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'video1', label: 'Video 1', dataType: 'Video', required: true },
      { id: 'video2', label: 'Video 2', dataType: 'Video', required: false },
      { id: 'video3', label: 'Video 3', dataType: 'Video', required: false },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'duration',
        label: 'Duration',
        type: 'enum',
        required: false,
        default: 5,
        options: [
          { label: '5 seconds', value: 5 },
          { label: '10 seconds', value: 10 },
        ],
      },
      {
        key: 'resolution',
        label: 'Resolution',
        type: 'enum',
        required: false,
        default: '1080p',
        options: [
          { label: '720p', value: '720p' },
          { label: '1080p', value: '1080p' },
        ],
      },
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: '16:9',
        options: [
          { label: '16:9', value: '16:9' },
          { label: '9:16', value: '9:16' },
          { label: '1:1', value: '1:1' },
          { label: '4:3', value: '4:3' },
          { label: '3:4', value: '3:4' },
        ],
      },
      {
        key: 'negative_prompt',
        label: 'Negative Prompt',
        type: 'string',
        required: false,
        placeholder: 'What to avoid',
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
      {
        key: 'enable_prompt_expansion',
        label: 'Prompt Expansion',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'multi_shots',
        label: 'Multi-Shot',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'enable_safety_checker',
        label: 'Safety Checker',
        type: 'boolean',
        required: false,
        default: true,
      },
    ],
  },
  'pixverse-v4-5': {
    id: 'pixverse-v4-5',
    displayName: 'PixVerse V4.5',
    category: 'video-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/pixverse/v4.5/text-to-video',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'duration',
        label: 'Duration',
        type: 'enum',
        required: false,
        default: 5,
        options: [
          { label: '5 seconds', value: 5 },
          { label: '8 seconds', value: 8 },
        ],
      },
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: '16:9',
        options: [
          { label: '16:9', value: '16:9' },
          { label: '4:3', value: '4:3' },
          { label: '1:1', value: '1:1' },
          { label: '3:4', value: '3:4' },
          { label: '9:16', value: '9:16' },
        ],
      },
      {
        key: 'resolution',
        label: 'Resolution',
        type: 'enum',
        required: false,
        default: '720p',
        options: [
          { label: '360p', value: '360p' },
          { label: '540p', value: '540p' },
          { label: '720p', value: '720p' },
          { label: '1080p', value: '1080p' },
        ],
      },
      {
        key: 'style',
        label: 'Style',
        type: 'enum',
        required: false,
        options: [
          { label: 'None', value: '' },
          { label: 'Anime', value: 'anime' },
          { label: '3D Animation', value: '3d_animation' },
          { label: 'Clay', value: 'clay' },
          { label: 'Comic', value: 'comic' },
          { label: 'Cyberpunk', value: 'cyberpunk' },
        ],
      },
      {
        key: 'negative_prompt',
        label: 'Negative Prompt',
        type: 'string',
        required: false,
        placeholder: 'What to avoid',
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
  },
  'seedance-v1-5': {
    id: 'seedance-v1-5',
    displayName: 'Seedance V1.5 Pro (I2V)',
    category: 'video-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/bytedance/seedance/v1.5/pro/image-to-video',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
      { id: 'end_image', label: 'End Image', dataType: 'Image', required: false },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'duration',
        label: 'Duration',
        type: 'enum',
        required: false,
        default: '5',
        options: [
          { label: '4 seconds', value: '4' },
          { label: '5 seconds', value: '5' },
          { label: '6 seconds', value: '6' },
          { label: '7 seconds', value: '7' },
          { label: '8 seconds', value: '8' },
          { label: '9 seconds', value: '9' },
          { label: '10 seconds', value: '10' },
          { label: '11 seconds', value: '11' },
          { label: '12 seconds', value: '12' },
        ],
      },
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: '16:9',
        options: [
          { label: '16:9', value: '16:9' },
          { label: '9:16', value: '9:16' },
          { label: '1:1', value: '1:1' },
          { label: '21:9', value: '21:9' },
          { label: '4:3', value: '4:3' },
          { label: '3:4', value: '3:4' },
          { label: 'Auto', value: 'auto' },
        ],
      },
      {
        key: 'resolution',
        label: 'Resolution',
        type: 'enum',
        required: false,
        default: '720p',
        options: [
          { label: '480p', value: '480p' },
          { label: '720p', value: '720p' },
          { label: '1080p', value: '1080p' },
        ],
      },
      {
        key: 'generate_audio',
        label: 'Generate Audio',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'camera_fixed',
        label: 'Camera Fixed',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
  },
  'kling-o3': {
    id: 'kling-o3',
    displayName: 'Kling Omni 3',
    category: 'video-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/kling-video/o3/standard/image-to-video',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: false },
      { id: 'end_image', label: 'End Frame', dataType: 'Image', required: false },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'duration',
        label: 'Duration',
        type: 'enum',
        required: false,
        default: '5',
        options: [
          { label: '3 seconds', value: '3' },
          { label: '5 seconds', value: '5' },
          { label: '10 seconds', value: '10' },
          { label: '15 seconds', value: '15' },
        ],
      },
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: '16:9',
        options: [
          { label: '16:9', value: '16:9' },
          { label: '9:16', value: '9:16' },
          { label: '1:1', value: '1:1' },
        ],
      },
      {
        key: 'generate_audio',
        label: 'Generate Audio',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'negative_prompt',
        label: 'Negative Prompt',
        type: 'string',
        required: false,
        default: 'blur, distort, and low quality',
      },
      {
        key: 'cfg_scale',
        label: 'CFG Scale',
        type: 'float',
        required: false,
        default: 0.5,
        min: 0,
        max: 1,
        step: 0.1,
      },
      {
        key: 'shot_type',
        label: 'Shot Type',
        type: 'enum',
        required: false,
        default: 'customize',
        options: [
          { label: 'Customize', value: 'customize' },
          { label: 'Intelligent (auto)', value: 'intelligent' },
        ],
      },
    ],
  },
  'ltx-2-3': {
    id: 'ltx-2-3',
    displayName: 'LTX 2.3',
    category: 'video-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/ltx-2.3/image-to-video',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'end_image', label: 'End Image', dataType: 'Image', required: false },
      { id: 'audio', label: 'Audio', dataType: 'Audio', required: false },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'duration',
        label: 'Duration',
        type: 'enum',
        required: false,
        default: '6',
        options: [
          { label: '6 seconds', value: '6' },
          { label: '8 seconds', value: '8' },
          { label: '10 seconds', value: '10' },
        ],
      },
      {
        key: 'resolution',
        label: 'Resolution',
        type: 'enum',
        required: false,
        default: '1080p',
        options: [
          { label: '1080p', value: '1080p' },
          { label: '1440p', value: '1440p' },
          { label: '2160p', value: '2160p' },
        ],
      },
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: '16:9', value: '16:9' },
          { label: '9:16', value: '9:16' },
        ],
      },
      {
        key: 'fps',
        label: 'FPS',
        type: 'enum',
        required: false,
        default: '25',
        options: [
          { label: '24', value: '24' },
          { label: '25', value: '25' },
          { label: '48', value: '48' },
          { label: '50', value: '50' },
        ],
      },
      {
        key: 'generate_audio',
        label: 'Generate Audio',
        type: 'boolean',
        required: false,
        default: true,
      },
    ],
  },

  'frame-extractor': {
    id: 'frame-extractor',
    displayName: 'Frame Extractor',
    category: 'transform',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    inputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'mode',
        label: 'Mode',
        type: 'enum',
        required: false,
        default: 'first_frame',
        options: [
          { label: 'First Frame', value: 'first_frame' },
          { label: 'Last Frame', value: 'last_frame' },
          { label: 'Middle Frame', value: 'middle_frame' },
          { label: 'At Timestamp', value: 'timestamp' },
        ],
      },
      {
        key: 'timestamp',
        label: 'Timestamp (s)',
        type: 'float',
        required: false,
        default: 0,
        min: 0,
        step: 0.1,
        placeholder: '0.0',
      },
    ],
  },

  'array-builder': {
    id: 'array-builder',
    displayName: 'Array Builder',
    category: 'utility',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    inputPorts: [
      { id: 'item1', label: 'Item 1', dataType: 'Any', required: true },
      { id: 'item2', label: 'Item 2', dataType: 'Any', required: false },
      { id: 'item3', label: 'Item 3', dataType: 'Any', required: false },
      { id: 'item4', label: 'Item 4', dataType: 'Any', required: false },
      { id: 'item5', label: 'Item 5', dataType: 'Any', required: false },
      { id: 'item6', label: 'Item 6', dataType: 'Any', required: false },
      { id: 'item7', label: 'Item 7', dataType: 'Any', required: false },
      { id: 'item8', label: 'Item 8', dataType: 'Any', required: false },
    ],
    outputPorts: [
      { id: 'array', label: 'Array', dataType: 'Array', required: false },
    ],
    params: [],
  },

  'array-selector': {
    id: 'array-selector',
    displayName: 'Array Selector',
    category: 'utility',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    inputPorts: [
      { id: 'array', label: 'Array', dataType: 'Array', required: true },
    ],
    outputPorts: [
      { id: 'item', label: 'Item', dataType: 'Any', required: false },
    ],
    params: [
      {
        key: 'mode',
        label: 'Mode',
        type: 'enum',
        required: false,
        default: 'first',
        options: [
          { label: 'First', value: 'first' },
          { label: 'Last', value: 'last' },
          { label: 'Random', value: 'random' },
          { label: 'By Index', value: 'index' },
        ],
      },
      {
        key: 'index',
        label: 'Index',
        type: 'integer',
        required: false,
        default: 0,
        min: 0,
      },
    ],
  },

  'image-compare': {
    id: 'image-compare',
    displayName: 'Image Compare',
    category: 'utility',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    inputPorts: [
      { id: 'imageA', label: 'Image A', dataType: 'Image', required: true },
      { id: 'imageB', label: 'Image B', dataType: 'Image', required: true },
    ],
    outputPorts: [],
    params: [],
  },

  'grok-imagine-video': {
    id: 'grok-imagine-video',
    displayName: 'Grok Imagine Video',
    category: 'video-gen',
    apiProvider: 'xai',
    apiEndpoint: 'https://api.x.ai/v1/videos/generations',
    envKeyName: 'XAI_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'duration',
        label: 'Duration',
        type: 'integer',
        required: false,
        default: 5,
        min: 1,
        max: 15,
      },
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: '16:9',
        options: [
          { label: '16:9', value: '16:9' },
          { label: '9:16', value: '9:16' },
          { label: '1:1', value: '1:1' },
          { label: '4:3', value: '4:3' },
          { label: '3:4', value: '3:4' },
          { label: '3:2', value: '3:2' },
          { label: '2:3', value: '2:3' },
        ],
      },
      {
        key: 'resolution',
        label: 'Resolution',
        type: 'enum',
        required: false,
        default: '480p',
        options: [
          { label: '480p', value: '480p' },
          { label: '720p', value: '720p' },
        ],
      },
    ],
  },

  'higgsfield': {
    id: 'higgsfield',
    displayName: 'Higgsfield',
    category: 'video-gen',
    apiProvider: 'higgsfield',
    apiEndpoint: 'https://platform.higgsfield.ai/higgsfield-ai/dop/standard',
    envKeyName: 'HIGGSFIELD_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'model',
        label: 'Model',
        type: 'enum',
        required: false,
        default: 'higgsfield-ai/dop/standard',
        options: [
          { label: 'DoP Standard (T2V + I2V)', value: 'higgsfield-ai/dop/standard' },
          { label: 'DoP Preview', value: 'higgsfield-ai/dop/preview' },
          { label: 'Kling v2.1 Pro (I2V)', value: 'kling-video/v2.1/pro/image-to-video' },
          { label: 'Seedance v1 Pro (I2V)', value: 'bytedance/seedance/v1/pro/image-to-video' },
        ],
      },
      {
        key: 'duration',
        label: 'Duration',
        type: 'integer',
        required: false,
        default: 5,
        min: 1,
        max: 15,
      },
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: '16:9',
        options: [
          { label: '16:9', value: '16:9' },
          { label: '9:16', value: '9:16' },
          { label: '1:1', value: '1:1' },
        ],
      },
    ],
  },

  'seedance-2-t2v': {
    id: 'seedance-2-t2v',
    displayName: 'Seedance 2.0 Text-to-Video',
    category: 'video-gen',
    apiProvider: 'fal',
    apiEndpoint: 'bytedance/seedance-2.0/text-to-video',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: '21:9', value: '21:9' },
          { label: '16:9', value: '16:9' },
          { label: '4:3', value: '4:3' },
          { label: '1:1', value: '1:1' },
          { label: '3:4', value: '3:4' },
          { label: '9:16', value: '9:16' },
        ],
      },
      {
        key: 'duration',
        label: 'Duration',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: '4s', value: '4' },
          { label: '5s', value: '5' },
          { label: '6s', value: '6' },
          { label: '8s', value: '8' },
          { label: '10s', value: '10' },
          { label: '12s', value: '12' },
          { label: '15s', value: '15' },
        ],
      },
      {
        key: 'resolution',
        label: 'Resolution',
        type: 'enum',
        required: false,
        default: '720p',
        options: [
          { label: '480p', value: '480p' },
          { label: '720p', value: '720p' },
          { label: '1080p', value: '1080p' },
        ],
      },
      {
        key: 'generate_audio',
        label: 'Generate Audio',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
  },

  'seedance-2-i2v': {
    id: 'seedance-2-i2v',
    displayName: 'Seedance 2.0 I2V',
    category: 'video-gen',
    apiProvider: 'fal',
    apiEndpoint: 'bytedance/seedance-2.0/image-to-video',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'end_image', label: 'End Frame', dataType: 'Image', required: false },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: '21:9', value: '21:9' },
          { label: '16:9', value: '16:9' },
          { label: '4:3', value: '4:3' },
          { label: '1:1', value: '1:1' },
          { label: '3:4', value: '3:4' },
          { label: '9:16', value: '9:16' },
        ],
      },
      {
        key: 'duration',
        label: 'Duration',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: '4s', value: '4' },
          { label: '5s', value: '5' },
          { label: '6s', value: '6' },
          { label: '8s', value: '8' },
          { label: '10s', value: '10' },
          { label: '12s', value: '12' },
          { label: '15s', value: '15' },
        ],
      },
      {
        key: 'resolution',
        label: 'Resolution',
        type: 'enum',
        required: false,
        default: '720p',
        options: [
          { label: '480p', value: '480p' },
          { label: '720p', value: '720p' },
          { label: '1080p', value: '1080p' },
        ],
      },
      {
        key: 'generate_audio',
        label: 'Generate Audio',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
  },

  'seedance-2-r2v': {
    id: 'seedance-2-r2v',
    displayName: 'Seedance 2.0 R2V',
    category: 'video-gen',
    apiProvider: 'fal',
    apiEndpoint: 'bytedance/seedance-2.0/reference-to-video',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'images', label: 'Reference Images', dataType: 'Image', required: true, multiple: true },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: '21:9', value: '21:9' },
          { label: '16:9', value: '16:9' },
          { label: '9:16', value: '9:16' },
          { label: '4:3', value: '4:3' },
          { label: '1:1', value: '1:1' },
          { label: '3:4', value: '3:4' },
        ],
      },
      {
        key: 'duration',
        label: 'Duration',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: '4s', value: '4' },
          { label: '6s', value: '6' },
          { label: '8s', value: '8' },
          { label: '10s', value: '10' },
          { label: '15s', value: '15' },
        ],
      },
      {
        key: 'resolution',
        label: 'Resolution',
        type: 'enum',
        required: false,
        default: '720p',
        options: [
          { label: '480p', value: '480p' },
          { label: '720p', value: '720p' },
          { label: '1080p', value: '1080p' },
        ],
      },
      {
        key: 'generate_audio',
        label: 'Generate Audio',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
  },

  'seedance-2-fast-t2v': {
    id: 'seedance-2-fast-t2v',
    displayName: 'Seedance 2.0 Fast T2V',
    category: 'video-gen',
    apiProvider: 'fal',
    apiEndpoint: 'bytedance/seedance-2.0/fast/text-to-video',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: '21:9', value: '21:9' },
          { label: '16:9', value: '16:9' },
          { label: '4:3', value: '4:3' },
          { label: '1:1', value: '1:1' },
          { label: '3:4', value: '3:4' },
          { label: '9:16', value: '9:16' },
        ],
      },
      {
        key: 'duration',
        label: 'Duration',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: '4s', value: '4' },
          { label: '5s', value: '5' },
          { label: '6s', value: '6' },
          { label: '8s', value: '8' },
          { label: '10s', value: '10' },
          { label: '12s', value: '12' },
          { label: '15s', value: '15' },
        ],
      },
      {
        key: 'resolution',
        label: 'Resolution',
        type: 'enum',
        required: false,
        default: '720p',
        options: [
          { label: '480p', value: '480p' },
          { label: '720p', value: '720p' },
        ],
      },
      {
        key: 'generate_audio',
        label: 'Generate Audio',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
  },

  'seedance-2-fast-i2v': {
    id: 'seedance-2-fast-i2v',
    displayName: 'Seedance 2.0 Fast I2V',
    category: 'video-gen',
    apiProvider: 'fal',
    apiEndpoint: 'bytedance/seedance-2.0/fast/image-to-video',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'end_image', label: 'End Frame', dataType: 'Image', required: false },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: '21:9', value: '21:9' },
          { label: '16:9', value: '16:9' },
          { label: '4:3', value: '4:3' },
          { label: '1:1', value: '1:1' },
          { label: '3:4', value: '3:4' },
          { label: '9:16', value: '9:16' },
        ],
      },
      {
        key: 'duration',
        label: 'Duration',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: '4s', value: '4' },
          { label: '5s', value: '5' },
          { label: '6s', value: '6' },
          { label: '8s', value: '8' },
          { label: '10s', value: '10' },
          { label: '12s', value: '12' },
          { label: '15s', value: '15' },
        ],
      },
      {
        key: 'resolution',
        label: 'Resolution',
        type: 'enum',
        required: false,
        default: '720p',
        options: [
          { label: '480p', value: '480p' },
          { label: '720p', value: '720p' },
        ],
      },
      {
        key: 'generate_audio',
        label: 'Generate Audio',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
  },

  'flux-kontext': {
    id: 'flux-kontext',
    displayName: 'FLUX Kontext',
    category: 'image-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/flux-pro/kontext',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: '1:1',
        options: [
          { label: '1:1', value: '1:1' },
          { label: '16:9', value: '16:9' },
          { label: '9:16', value: '9:16' },
          { label: '4:3', value: '4:3' },
          { label: '3:4', value: '3:4' },
          { label: '3:2', value: '3:2' },
          { label: '2:3', value: '2:3' },
          { label: '21:9', value: '21:9' },
          { label: '9:21', value: '9:21' },
        ],
      },
      {
        key: 'num_images',
        label: 'Count',
        type: 'integer',
        required: false,
        default: 1,
        min: 1,
        max: 4,
      },
      {
        key: 'guidance_scale',
        label: 'Guidance Scale',
        type: 'float',
        required: false,
        default: 3.5,
        min: 1,
        max: 20,
        step: 0.5,
      },
      {
        key: 'enhance_prompt',
        label: 'Enhance Prompt',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'output_format',
        label: 'Format',
        type: 'enum',
        required: false,
        default: 'jpeg',
        options: [
          { label: 'JPEG', value: 'jpeg' },
          { label: 'PNG', value: 'png' },
        ],
      },
      {
        key: 'safety_tolerance',
        label: 'Safety',
        type: 'enum',
        required: false,
        default: '2',
        options: [
          { label: '1 (Strict)', value: '1' },
          { label: '2', value: '2' },
          { label: '3', value: '3' },
          { label: '4', value: '4' },
          { label: '5', value: '5' },
          { label: '6 (Permissive)', value: '6' },
        ],
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
  },

  'flux-2-pro': {
    id: 'flux-2-pro',
    displayName: 'FLUX 2 Pro',
    category: 'image-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/flux-2-pro',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'image_size',
        label: 'Size',
        type: 'enum',
        required: false,
        default: 'landscape_4_3',
        options: [
          { label: 'Square HD', value: 'square_hd' },
          { label: 'Square', value: 'square' },
          { label: 'Portrait 4:3', value: 'portrait_4_3' },
          { label: 'Portrait 16:9', value: 'portrait_16_9' },
          { label: 'Landscape 4:3', value: 'landscape_4_3' },
          { label: 'Landscape 16:9', value: 'landscape_16_9' },
        ],
      },
      {
        key: 'output_format',
        label: 'Format',
        type: 'enum',
        required: false,
        default: 'jpeg',
        options: [
          { label: 'JPEG', value: 'jpeg' },
          { label: 'PNG', value: 'png' },
        ],
      },
      {
        key: 'safety_tolerance',
        label: 'Safety',
        type: 'enum',
        required: false,
        default: '2',
        options: [
          { label: '1 (Strict)', value: '1' },
          { label: '2', value: '2' },
          { label: '3', value: '3' },
          { label: '4', value: '4' },
          { label: '5 (Permissive)', value: '5' },
        ],
      },
      {
        key: 'enable_safety_checker',
        label: 'Safety Checker',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
  },

  'gpt-image-1-5': {
    id: 'gpt-image-1-5',
    displayName: 'GPT Image 1.5',
    category: 'image-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/gpt-image-1.5',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'image_size',
        label: 'Size',
        type: 'enum',
        required: false,
        default: '1024x1024',
        options: [
          { label: '1024x1024', value: '1024x1024' },
          { label: '1536x1024', value: '1536x1024' },
          { label: '1024x1536', value: '1024x1536' },
        ],
      },
      {
        key: 'quality',
        label: 'Quality',
        type: 'enum',
        required: false,
        default: 'high',
        options: [
          { label: 'Low', value: 'low' },
          { label: 'Medium', value: 'medium' },
          { label: 'High', value: 'high' },
        ],
      },
      {
        key: 'background',
        label: 'Background',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: 'Transparent', value: 'transparent' },
          { label: 'Opaque', value: 'opaque' },
        ],
      },
      {
        key: 'num_images',
        label: 'Count',
        type: 'integer',
        required: false,
        default: 1,
        min: 1,
        max: 4,
      },
      {
        key: 'output_format',
        label: 'Format',
        type: 'enum',
        required: false,
        default: 'png',
        options: [
          { label: 'PNG', value: 'png' },
          { label: 'JPEG', value: 'jpeg' },
          { label: 'WebP', value: 'webp' },
        ],
      },
    ],
  },

  'gpt-image-1-5-edit': {
    id: 'gpt-image-1-5-edit',
    displayName: 'GPT Image 1.5 Edit',
    category: 'image-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/gpt-image-1.5/edit',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'images', label: 'Reference Images', dataType: 'Image', required: true, multiple: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'image_size',
        label: 'Size',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: '1024x1024', value: '1024x1024' },
          { label: '1536x1024', value: '1536x1024' },
          { label: '1024x1536', value: '1024x1536' },
        ],
      },
      {
        key: 'quality',
        label: 'Quality',
        type: 'enum',
        required: false,
        default: 'high',
        options: [
          { label: 'Low', value: 'low' },
          { label: 'Medium', value: 'medium' },
          { label: 'High', value: 'high' },
        ],
      },
      {
        key: 'input_fidelity',
        label: 'Input Fidelity',
        type: 'enum',
        required: false,
        default: 'high',
        options: [
          { label: 'Low', value: 'low' },
          { label: 'High', value: 'high' },
        ],
      },
      {
        key: 'background',
        label: 'Background',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: 'Transparent', value: 'transparent' },
          { label: 'Opaque', value: 'opaque' },
        ],
      },
      {
        key: 'num_images',
        label: 'Count',
        type: 'integer',
        required: false,
        default: 1,
        min: 1,
        max: 4,
      },
      {
        key: 'output_format',
        label: 'Format',
        type: 'enum',
        required: false,
        default: 'png',
        options: [
          { label: 'PNG', value: 'png' },
          { label: 'JPEG', value: 'jpeg' },
          { label: 'WebP', value: 'webp' },
        ],
      },
    ],
  },

  'gpt-image-2-generate': {
    id: 'gpt-image-2-generate',
    displayName: 'GPT Image 2',
    category: 'image-gen',
    apiProvider: 'openai',
    apiEndpoint: '/v1/images/generations',
    envKeyName: 'OPENAI_API_KEY',
    executionPattern: 'stream',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'size',
        label: 'Size',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: '1024x1024', value: '1024x1024' },
          { label: '1536x1024', value: '1536x1024' },
          { label: '1024x1536', value: '1024x1536' },
          { label: '2048x2048', value: '2048x2048' },
          { label: '2048x1152', value: '2048x1152' },
          { label: '3840x2160 (4K landscape)', value: '3840x2160' },
          { label: '2160x3840 (4K portrait)', value: '2160x3840' },
        ],
      },
      {
        key: 'quality',
        label: 'Quality',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: 'Low', value: 'low' },
          { label: 'Medium', value: 'medium' },
          { label: 'High', value: 'high' },
        ],
      },
      {
        key: 'output_format',
        label: 'Format',
        type: 'enum',
        required: false,
        default: 'png',
        options: [
          { label: 'PNG', value: 'png' },
          { label: 'JPEG', value: 'jpeg' },
          { label: 'WebP', value: 'webp' },
        ],
      },
      {
        key: 'output_compression',
        label: 'Compression',
        type: 'integer',
        required: false,
        default: 90,
        min: 0,
        max: 100,
      },
      {
        key: 'moderation',
        label: 'Moderation',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: 'Low', value: 'low' },
        ],
      },
    ],
  },

  'gpt-image-2-edit': {
    id: 'gpt-image-2-edit',
    displayName: 'GPT Image 2 Edit',
    category: 'image-gen',
    apiProvider: 'openai',
    apiEndpoint: '/v1/images/edits',
    envKeyName: 'OPENAI_API_KEY',
    executionPattern: 'stream',
    inputPorts: [
      { id: 'images', label: 'Images', dataType: 'Image', required: true, multiple: true },
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'mask', label: 'Mask', dataType: 'Mask', required: false },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'size',
        label: 'Size',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: '1024x1024', value: '1024x1024' },
          { label: '1536x1024', value: '1536x1024' },
          { label: '1024x1536', value: '1024x1536' },
          { label: '2048x2048', value: '2048x2048' },
          { label: '2048x1152', value: '2048x1152' },
          { label: '3840x2160 (4K landscape)', value: '3840x2160' },
          { label: '2160x3840 (4K portrait)', value: '2160x3840' },
        ],
      },
      {
        key: 'quality',
        label: 'Quality',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: 'Low', value: 'low' },
          { label: 'Medium', value: 'medium' },
          { label: 'High', value: 'high' },
        ],
      },
      {
        key: 'output_format',
        label: 'Format',
        type: 'enum',
        required: false,
        default: 'png',
        options: [
          { label: 'PNG', value: 'png' },
          { label: 'JPEG', value: 'jpeg' },
          { label: 'WebP', value: 'webp' },
        ],
      },
      {
        key: 'output_compression',
        label: 'Compression',
        type: 'integer',
        required: false,
        default: 90,
        min: 0,
        max: 100,
      },
      {
        key: 'moderation',
        label: 'Moderation',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: 'Low', value: 'low' },
        ],
      },
    ],
  },

  'gpt-image-2-fal-generate': {
    id: 'gpt-image-2-fal-generate',
    displayName: 'GPT Image 2 (FAL)',
    category: 'image-gen',
    apiProvider: 'fal',
    apiEndpoint: 'openai/gpt-image-2',
    envKeyName: 'FAL_KEY',
    executionPattern: 'stream',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'image_size',
        label: 'Size',
        type: 'enum',
        required: false,
        default: 'landscape_4_3',
        options: [
          { label: 'Square HD (1024x1024)', value: 'square_hd' },
          { label: 'Square (512x512)', value: 'square' },
          { label: 'Portrait 4:3 (768x1024)', value: 'portrait_4_3' },
          { label: 'Portrait 16:9 (576x1024)', value: 'portrait_16_9' },
          { label: 'Landscape 4:3 (1024x768)', value: 'landscape_4_3' },
          { label: 'Landscape 16:9 (1024x576)', value: 'landscape_16_9' },
        ],
      },
      {
        key: 'quality',
        label: 'Quality',
        type: 'enum',
        required: false,
        default: 'high',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: 'Low', value: 'low' },
          { label: 'Medium', value: 'medium' },
          { label: 'High', value: 'high' },
        ],
      },
      {
        key: 'num_images',
        label: 'Count',
        type: 'integer',
        required: false,
        default: 1,
        min: 1,
        max: 4,
      },
      {
        key: 'output_format',
        label: 'Format',
        type: 'enum',
        required: false,
        default: 'png',
        options: [
          { label: 'PNG', value: 'png' },
          { label: 'JPEG', value: 'jpeg' },
          { label: 'WebP', value: 'webp' },
        ],
      },
      {
        key: 'partial_images',
        label: 'Preview Frames',
        type: 'integer',
        required: false,
        default: 2,
        min: 0,
        max: 3,
      },
    ],
  },

  'gpt-image-2-fal-edit': {
    id: 'gpt-image-2-fal-edit',
    displayName: 'GPT Image 2 Edit (FAL)',
    category: 'image-gen',
    apiProvider: 'fal',
    apiEndpoint: 'openai/gpt-image-2/edit',
    envKeyName: 'FAL_KEY',
    executionPattern: 'stream',
    inputPorts: [
      { id: 'images', label: 'Reference Images', dataType: 'Image', required: true, multiple: true },
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'image_size',
        label: 'Size',
        type: 'enum',
        required: false,
        default: 'auto',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: 'Square HD (1024x1024)', value: 'square_hd' },
          { label: 'Square (512x512)', value: 'square' },
          { label: 'Portrait 4:3 (768x1024)', value: 'portrait_4_3' },
          { label: 'Portrait 16:9 (576x1024)', value: 'portrait_16_9' },
          { label: 'Landscape 4:3 (1024x768)', value: 'landscape_4_3' },
          { label: 'Landscape 16:9 (1024x576)', value: 'landscape_16_9' },
        ],
      },
      {
        key: 'quality',
        label: 'Quality',
        type: 'enum',
        required: false,
        default: 'high',
        options: [
          { label: 'Auto', value: 'auto' },
          { label: 'Low', value: 'low' },
          { label: 'Medium', value: 'medium' },
          { label: 'High', value: 'high' },
        ],
      },
      {
        key: 'num_images',
        label: 'Count',
        type: 'integer',
        required: false,
        default: 1,
        min: 1,
        max: 4,
      },
      {
        key: 'output_format',
        label: 'Format',
        type: 'enum',
        required: false,
        default: 'png',
        options: [
          { label: 'PNG', value: 'png' },
          { label: 'JPEG', value: 'jpeg' },
          { label: 'WebP', value: 'webp' },
        ],
      },
      {
        key: 'partial_images',
        label: 'Preview Frames',
        type: 'integer',
        required: false,
        default: 2,
        min: 0,
        max: 3,
      },
    ],
  },

  'krea-2-generate': {
    id: 'krea-2-generate',
    displayName: 'Krea 2',
    category: 'image-gen',
    apiProvider: 'krea',
    apiEndpoint: '/generate/image/krea/krea-2/{variant}',
    envKeyName: 'KREA_API_TOKEN',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'style_images', label: 'Style Images', dataType: 'Image', required: false, multiple: true, maxConnections: 10 },
      { id: 'image_style_references', label: 'Image Style Refs', dataType: 'Any', required: false, multiple: true, maxConnections: 10 },
      { id: 'styles', label: 'Styles', dataType: 'Any', required: false, multiple: true },
      { id: 'moodboard', label: 'Moodboard', dataType: 'Any', required: false, maxConnections: 1 },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
      { id: 'job', label: 'Job', dataType: 'Any', required: false },
    ],
    params: [
      {
        key: 'variant',
        label: 'Variant',
        type: 'enum',
        required: false,
        default: 'medium',
        options: [
          { label: 'Medium', value: 'medium' },
          { label: 'Large', value: 'large' },
        ],
      },
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: '1:1',
        options: [
          { label: '1:1', value: '1:1' },
          { label: '4:3', value: '4:3' },
          { label: '3:2', value: '3:2' },
          { label: '16:9', value: '16:9' },
          { label: '2.35:1', value: '2.35:1' },
          { label: '4:5', value: '4:5' },
          { label: '2:3', value: '2:3' },
          { label: '9:16', value: '9:16' },
        ],
      },
      {
        key: 'resolution',
        label: 'Resolution',
        type: 'enum',
        required: false,
        default: '1K',
        options: [
          { label: '1K', value: '1K' },
        ],
      },
      {
        key: 'creativity',
        label: 'Creativity',
        type: 'enum',
        required: false,
        default: 'medium',
        options: [
          { label: 'Raw', value: 'raw' },
          { label: 'Low', value: 'low' },
          { label: 'Medium', value: 'medium' },
          { label: 'High', value: 'high' },
        ],
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        min: 0,
        max: 2147483647,
        placeholder: 'Random',
      },
      {
        key: 'style_reference_strength',
        label: 'Style Ref Strength',
        type: 'float',
        required: false,
        default: 0.5,
        min: 0,
        max: 1,
        step: 0.05,
      },
      {
        key: 'style_id',
        label: 'Style ID',
        type: 'string',
        required: false,
        placeholder: 'Existing Krea style ID',
      },
      {
        key: 'style_strength',
        label: 'Style Strength',
        type: 'float',
        required: false,
        default: 1,
        min: -2,
        max: 2,
        step: 0.1,
      },
      {
        key: 'moodboard_id',
        label: 'Moodboard ID',
        type: 'string',
        required: false,
        placeholder: 'Existing Krea moodboard ID',
      },
      {
        key: 'moodboard_strength',
        label: 'Moodboard Strength',
        type: 'float',
        required: false,
        default: 0.23,
        min: 0,
        max: 1,
        step: 0.01,
      },
    ],
    docUrl: 'docs/model-providers/krea/krea-2.md',
  },

  'krea-image-style-reference': {
    id: 'krea-image-style-reference',
    displayName: 'Krea Image Style Ref',
    category: 'utility',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    inputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
    ],
    outputPorts: [
      { id: 'image_style_reference', label: 'Image Style Ref', dataType: 'Any', required: false },
    ],
    params: [
      {
        key: 'strength',
        label: 'Strength',
        type: 'float',
        required: false,
        default: 0.5,
        min: 0,
        max: 1,
        step: 0.05,
      },
    ],
    docUrl: 'docs/model-providers/krea/krea-2.md',
  },

  'krea-style': {
    id: 'krea-style',
    displayName: 'Krea Style',
    category: 'utility',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    inputPorts: [],
    outputPorts: [
      { id: 'style', label: 'Style', dataType: 'Any', required: false },
      { id: 'style_id', label: 'Style ID', dataType: 'Text', required: false },
    ],
    params: [
      {
        key: 'style_id',
        label: 'Style ID',
        type: 'string',
        required: true,
        placeholder: 'Krea style ID',
      },
      {
        key: 'strength',
        label: 'Strength',
        type: 'float',
        required: false,
        default: 1,
        min: -2,
        max: 2,
        step: 0.1,
      },
    ],
    docUrl: 'docs/model-providers/krea/krea-2.md',
  },

  'krea-moodboard': {
    id: 'krea-moodboard',
    displayName: 'Krea Moodboard',
    category: 'utility',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    inputPorts: [],
    outputPorts: [
      { id: 'moodboard', label: 'Moodboard', dataType: 'Any', required: false },
      { id: 'moodboard_id', label: 'Moodboard ID', dataType: 'Text', required: false },
    ],
    params: [
      {
        key: 'moodboard_id',
        label: 'Moodboard ID',
        type: 'string',
        required: true,
        placeholder: 'Krea moodboard ID',
      },
      {
        key: 'strength',
        label: 'Strength',
        type: 'float',
        required: false,
        default: 0.23,
        min: 0,
        max: 1,
        step: 0.01,
      },
    ],
    docUrl: 'docs/model-providers/krea/krea-2.md',
  },

  'krea-style-search': {
    id: 'krea-style-search',
    displayName: 'Krea Style Search',
    category: 'analyzer',
    apiProvider: 'krea',
    apiEndpoint: '/styles',
    envKeyName: 'KREA_API_TOKEN',
    executionPattern: 'sync',
    inputPorts: [],
    outputPorts: [
      { id: 'styles', label: 'Styles', dataType: 'Array', required: false },
      { id: 'text', label: 'Summary', dataType: 'Text', required: false },
    ],
    params: [
      {
        key: 'filter',
        label: 'Filter',
        type: 'enum',
        required: false,
        default: 'all',
        options: [
          { label: 'All', value: 'all' },
          { label: 'User', value: 'user' },
          { label: 'Community', value: 'community' },
          { label: 'Krea', value: 'krea' },
          { label: 'Shared', value: 'shared' },
          { label: 'Public', value: 'public' },
          { label: 'Gallery', value: 'gallery' },
        ],
      },
      {
        key: 'model',
        label: 'Model',
        type: 'string',
        required: false,
        placeholder: 'flux_dev, qwen, z-image, wan',
      },
      {
        key: 'ids',
        label: 'IDs',
        type: 'string',
        required: false,
        placeholder: 'Comma-separated style IDs',
      },
      {
        key: 'user',
        label: 'User',
        type: 'string',
        required: false,
      },
      {
        key: 'liked',
        label: 'Liked Only',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'limit',
        label: 'Limit',
        type: 'integer',
        required: false,
        default: 25,
        min: 1,
        max: 1000,
      },
      {
        key: 'cursor',
        label: 'Cursor',
        type: 'string',
        required: false,
      },
    ],
    docUrl: 'docs/model-providers/krea/krea-2.md',
  },

  'krea-style-train': {
    id: 'krea-style-train',
    displayName: 'Krea Style Train',
    category: 'image-gen',
    apiProvider: 'krea',
    apiEndpoint: '/styles/train',
    envKeyName: 'KREA_API_TOKEN',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'images', label: 'Training Images', dataType: 'Image', required: true, multiple: true },
    ],
    outputPorts: [
      { id: 'style', label: 'Style', dataType: 'Any', required: false },
      { id: 'style_id', label: 'Style ID', dataType: 'Text', required: false },
      { id: 'job', label: 'Job', dataType: 'Any', required: false },
    ],
    params: [
      {
        key: 'name',
        label: 'Name',
        type: 'string',
        required: true,
        placeholder: 'Style name',
      },
      {
        key: 'model',
        label: 'Training Model',
        type: 'enum',
        required: false,
        default: 'flux_dev',
        options: [
          { label: 'FLUX Dev', value: 'flux_dev' },
          { label: 'FLUX Schnell', value: 'flux_schnell' },
          { label: 'Wan', value: 'wan' },
          { label: 'Wan 2.2', value: 'wan22' },
          { label: 'Qwen', value: 'qwen' },
          { label: 'Z-Image', value: 'z-image' },
        ],
      },
      {
        key: 'training_type',
        label: 'Type',
        type: 'enum',
        required: false,
        default: 'Style',
        options: [
          { label: 'Style', value: 'Style' },
          { label: 'Object', value: 'Object' },
          { label: 'Character', value: 'Character' },
          { label: 'Default', value: 'Default' },
        ],
      },
      {
        key: 'trigger_word',
        label: 'Trigger Word',
        type: 'string',
        required: false,
      },
      {
        key: 'max_train_steps',
        label: 'Max Steps',
        type: 'integer',
        required: false,
        min: 1,
        max: 2000,
      },
      {
        key: 'learning_rate',
        label: 'Learning Rate',
        type: 'float',
        required: false,
        visibleWhen: { model: ['flux_dev', 'flux_schnell', 'wan', 'wan22'] },
      },
      {
        key: 'batch_size',
        label: 'Batch Size',
        type: 'integer',
        required: false,
        min: 1,
        visibleWhen: { model: ['flux_dev', 'flux_schnell', 'wan', 'wan22'] },
      },
      {
        key: 'generation_strength',
        label: 'Output Strength',
        type: 'float',
        required: false,
        default: 1,
        min: -2,
        max: 2,
        step: 0.1,
      },
      {
        key: 'share_with_workspace',
        label: 'Share Workspace',
        type: 'boolean',
        required: false,
        default: false,
      },
    ],
    docUrl: 'docs/model-providers/krea/krea-2.md',
  },

  'clarity-upscaler': {
    id: 'clarity-upscaler',
    displayName: 'Clarity Upscaler',
    category: 'transform',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/clarity-upscaler',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'prompt',
        label: 'Enhancement Prompt',
        type: 'string',
        required: false,
        default: 'masterpiece, best quality, highres',
      },
      {
        key: 'upscale_factor',
        label: 'Upscale Factor',
        type: 'float',
        required: false,
        default: 2,
        min: 1,
        max: 4,
        step: 0.5,
      },
      {
        key: 'creativity',
        label: 'Creativity (added detail)',
        type: 'float',
        required: false,
        default: 0.35,
        min: 0,
        max: 1,
        step: 0.05,
      },
      {
        key: 'resemblance',
        label: 'Resemblance (fidelity)',
        type: 'float',
        required: false,
        default: 0.6,
        min: 0,
        max: 1,
        step: 0.05,
      },
      {
        key: 'num_inference_steps',
        label: 'Steps',
        type: 'integer',
        required: false,
        default: 18,
        min: 10,
        max: 50,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
  },

  'seedvr-video-upscale': {
    id: 'seedvr-video-upscale',
    displayName: 'SeedVR2 Video Upscale',
    category: 'transform',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/seedvr/upscale/video',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: true },
    ],
    outputPorts: [
      { id: 'video', label: 'Video', dataType: 'Video', required: false },
    ],
    params: [
      {
        key: 'upscale_mode',
        label: 'Mode',
        type: 'enum',
        required: false,
        default: 'factor',
        options: [
          { label: 'Factor (multiplier)', value: 'factor' },
          { label: 'Target resolution', value: 'target' },
        ],
      },
      {
        key: 'upscale_factor',
        label: 'Upscale Factor',
        type: 'float',
        required: false,
        default: 2,
        min: 1,
        max: 4,
        step: 0.5,
      },
      {
        key: 'target_resolution',
        label: 'Target Resolution',
        type: 'enum',
        required: false,
        default: '1080p',
        options: [
          { label: '720p', value: '720p' },
          { label: '1080p', value: '1080p' },
          { label: '1440p', value: '1440p' },
          { label: '2160p (4K)', value: '2160p' },
        ],
      },
      {
        key: 'noise_scale',
        label: 'Noise Scale',
        type: 'float',
        required: false,
        default: 0.1,
        min: 0,
        max: 1,
        step: 0.05,
      },
      {
        key: 'output_quality',
        label: 'Output Quality',
        type: 'enum',
        required: false,
        default: 'high',
        options: [
          { label: 'Low', value: 'low' },
          { label: 'Medium', value: 'medium' },
          { label: 'High', value: 'high' },
          { label: 'Maximum', value: 'maximum' },
        ],
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
  },

  'seedvr2-upscale': {
    id: 'seedvr2-upscale',
    displayName: 'SeedVR2 Upscale',
    category: 'transform',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/seedvr/upscale/image',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Upscaled Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'upscale_mode',
        label: 'Mode',
        type: 'enum',
        required: false,
        default: 'factor',
        options: [
          { label: 'Factor', value: 'factor' },
          { label: 'Target Resolution', value: 'target' },
        ],
      },
      {
        key: 'upscale_factor',
        label: 'Factor',
        type: 'float',
        required: false,
        default: 2,
        min: 1,
        max: 4,
        step: 0.5,
        visibleWhen: { upscale_mode: ['factor'] },
      },
      {
        key: 'target_resolution',
        label: 'Target Resolution',
        type: 'enum',
        required: false,
        default: '1080p',
        visibleWhen: { upscale_mode: ['target'] },
        options: [
          { label: '720p', value: '720p' },
          { label: '1080p', value: '1080p' },
          { label: '1440p', value: '1440p' },
          { label: '2160p (4K)', value: '2160p' },
        ],
      },
      {
        key: 'noise_scale',
        label: 'Noise Scale',
        type: 'float',
        required: false,
        default: 0.1,
        min: 0,
        max: 1,
        step: 0.05,
      },
      {
        key: 'output_format',
        label: 'Format',
        type: 'enum',
        required: false,
        default: 'jpg',
        options: [
          { label: 'JPG', value: 'jpg' },
          { label: 'PNG', value: 'png' },
          { label: 'WebP', value: 'webp' },
        ],
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
  },

  'seedream-4-5': {
    id: 'seedream-4-5',
    displayName: 'Seedream 4.5',
    category: 'image-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/bytedance/seedream/v4.5/text-to-image',
    envKeyName: 'FAL_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'image_size',
        label: 'Size',
        type: 'enum',
        required: false,
        default: 'square_hd',
        options: [
          { label: 'Square HD (2048x2048)', value: 'square_hd' },
          { label: 'Square (512x512)', value: 'square' },
          { label: 'Portrait 4:3', value: 'portrait_4_3' },
          { label: 'Portrait 16:9', value: 'portrait_16_9' },
          { label: 'Landscape 4:3', value: 'landscape_4_3' },
          { label: 'Landscape 16:9', value: 'landscape_16_9' },
          { label: 'Auto 2K', value: 'auto_2K' },
          { label: 'Auto 4K', value: 'auto_4K' },
        ],
      },
      {
        key: 'num_images',
        label: 'Generations',
        type: 'integer',
        required: false,
        default: 1,
        min: 1,
        max: 6,
      },
      {
        key: 'max_images',
        label: 'Images per Generation',
        type: 'integer',
        required: false,
        default: 1,
        min: 1,
        max: 6,
      },
      {
        key: 'enable_safety_checker',
        label: 'Safety Checker',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
  },

  'ideogram-v4': {
    id: 'ideogram-v4',
    displayName: 'Ideogram 4',
    category: 'image-gen',
    apiProvider: 'fal',
    apiEndpoint: 'ideogram/v4',
    envKeyName: ['IDEOGRAM_API_KEY', 'FAL_KEY'],
    executionPattern: 'async-poll',
    directKeyName: 'IDEOGRAM_API_KEY',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [],
    sharedParams: [],
    falParams: [
      {
        key: 'rendering_speed',
        label: 'Rendering Speed',
        type: 'enum',
        required: false,
        default: 'BALANCED',
        options: [
          { label: 'Turbo', value: 'TURBO' },
          { label: 'Balanced', value: 'BALANCED' },
          { label: 'Quality', value: 'QUALITY' },
        ],
      },
      {
        key: 'image_size',
        label: 'Size',
        type: 'enum',
        required: false,
        default: 'square_hd',
        options: [
          { label: 'Square HD', value: 'square_hd' },
          { label: 'Square', value: 'square' },
          { label: 'Portrait 4:3', value: 'portrait_4_3' },
          { label: 'Portrait 16:9', value: 'portrait_16_9' },
          { label: 'Landscape 4:3', value: 'landscape_4_3' },
          { label: 'Landscape 16:9', value: 'landscape_16_9' },
        ],
      },
      {
        key: 'expansion_model',
        label: 'Prompt Expansion',
        type: 'enum',
        required: false,
        default: 'Medium',
        options: [
          { label: 'Medium', value: 'Medium' },
          { label: 'Large', value: 'Large' },
        ],
      },
      {
        key: 'num_images',
        label: 'Images',
        type: 'integer',
        required: false,
        default: 1,
        min: 1,
        max: 4,
      },
      {
        key: 'output_format',
        label: 'Format',
        type: 'enum',
        required: false,
        default: 'png',
        options: [
          { label: 'PNG', value: 'png' },
          { label: 'JPEG', value: 'jpeg' },
        ],
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
      {
        key: 'enable_safety_checker',
        label: 'Safety Checker',
        type: 'boolean',
        required: false,
        default: true,
      },
    ],
    directParams: [
      {
        key: 'resolution',
        label: 'Resolution (2K)',
        type: 'enum',
        required: false,
        default: '2048x2048',
        options: [
          { label: '2048x2048', value: '2048x2048' },
          { label: '1440x2880', value: '1440x2880' },
          { label: '2880x1440', value: '2880x1440' },
          { label: '1664x2496', value: '1664x2496' },
          { label: '2496x1664', value: '2496x1664' },
          { label: '1792x2240', value: '1792x2240' },
          { label: '2240x1792', value: '2240x1792' },
          { label: '1440x2560', value: '1440x2560' },
          { label: '2560x1440', value: '2560x1440' },
          { label: '1600x2560', value: '1600x2560' },
          { label: '2560x1600', value: '2560x1600' },
        ],
      },
      {
        key: 'rendering_speed',
        label: 'Rendering Speed',
        type: 'enum',
        required: false,
        default: 'DEFAULT',
        options: [
          { label: 'Turbo', value: 'TURBO' },
          { label: 'Default', value: 'DEFAULT' },
          { label: 'Quality', value: 'QUALITY' },
        ],
      },
    ],
  },

  'ideogram-edit': {
    id: 'ideogram-edit',
    displayName: 'Ideogram Edit (Inpaint)',
    category: 'image-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/ideogram/v3/edit',
    envKeyName: ['IDEOGRAM_API_KEY', 'FAL_KEY'],
    executionPattern: 'async-poll',
    directKeyName: 'IDEOGRAM_API_KEY',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'image', label: 'Base Image', dataType: 'Image', required: true },
      { id: 'mask', label: 'Mask (black = edit)', dataType: 'Image', required: true },
      { id: 'images', label: 'Style Refs', dataType: 'Image', required: false, multiple: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [],
    sharedParams: [
      {
        key: 'num_images',
        label: 'Images',
        type: 'integer',
        required: false,
        default: 1,
        min: 1,
        max: 4,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
    falParams: [
      {
        key: 'rendering_speed',
        label: 'Rendering Speed',
        type: 'enum',
        required: false,
        default: 'BALANCED',
        options: [
          { label: 'Turbo', value: 'TURBO' },
          { label: 'Balanced', value: 'BALANCED' },
          { label: 'Quality', value: 'QUALITY' },
        ],
      },
      {
        key: 'expand_prompt',
        label: 'Magic Prompt',
        type: 'boolean',
        required: false,
        default: true,
      },
    ],
    directParams: [
      {
        key: 'rendering_speed',
        label: 'Rendering Speed',
        type: 'enum',
        required: false,
        default: 'DEFAULT',
        options: [
          { label: 'Turbo', value: 'TURBO' },
          { label: 'Default', value: 'DEFAULT' },
          { label: 'Quality', value: 'QUALITY' },
        ],
      },
      {
        key: 'magic_prompt',
        label: 'Magic Prompt',
        type: 'enum',
        required: false,
        default: 'AUTO',
        options: [
          { label: 'Auto', value: 'AUTO' },
          { label: 'On', value: 'ON' },
          { label: 'Off', value: 'OFF' },
        ],
      },
    ],
  },

  'ideogram-remix': {
    id: 'ideogram-remix',
    displayName: 'Ideogram Remix',
    category: 'image-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/ideogram/v3/remix',
    envKeyName: ['IDEOGRAM_API_KEY', 'FAL_KEY'],
    executionPattern: 'async-poll',
    directKeyName: 'IDEOGRAM_API_KEY',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'image', label: 'Source Image', dataType: 'Image', required: true },
      { id: 'images', label: 'Style Refs', dataType: 'Image', required: false, multiple: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [],
    sharedParams: [],
    falParams: [
      {
        key: 'strength',
        label: 'Image Strength',
        type: 'float',
        required: false,
        default: 0.8,
        min: 0,
        max: 1,
        step: 0.05,
      },
      {
        key: 'image_size',
        label: 'Size',
        type: 'enum',
        required: false,
        default: 'square_hd',
        options: [
          { label: 'Square HD', value: 'square_hd' },
          { label: 'Square', value: 'square' },
          { label: 'Portrait 4:3', value: 'portrait_4_3' },
          { label: 'Portrait 16:9', value: 'portrait_16_9' },
          { label: 'Landscape 4:3', value: 'landscape_4_3' },
          { label: 'Landscape 16:9', value: 'landscape_16_9' },
        ],
      },
      {
        key: 'style',
        label: 'Style',
        type: 'enum',
        required: false,
        default: 'AUTO',
        options: [
          { label: 'Auto', value: 'AUTO' },
          { label: 'General', value: 'GENERAL' },
          { label: 'Realistic', value: 'REALISTIC' },
          { label: 'Design', value: 'DESIGN' },
        ],
      },
      {
        key: 'negative_prompt',
        label: 'Negative Prompt',
        type: 'string',
        required: false,
        placeholder: 'What to avoid',
      },
      {
        key: 'rendering_speed',
        label: 'Rendering Speed',
        type: 'enum',
        required: false,
        default: 'BALANCED',
        options: [
          { label: 'Turbo', value: 'TURBO' },
          { label: 'Balanced', value: 'BALANCED' },
          { label: 'Quality', value: 'QUALITY' },
        ],
      },
      {
        key: 'expand_prompt',
        label: 'Magic Prompt',
        type: 'boolean',
        required: false,
        default: true,
      },
      {
        key: 'num_images',
        label: 'Images',
        type: 'integer',
        required: false,
        default: 1,
        min: 1,
        max: 4,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
    directParams: [
      {
        key: 'image_weight',
        label: 'Image Weight',
        type: 'integer',
        required: false,
        min: 1,
        max: 100,
        placeholder: 'Auto (from prompt)',
      },
      {
        key: 'resolution',
        label: 'Resolution (2K)',
        type: 'enum',
        required: false,
        default: '',
        options: [
          { label: 'Auto', value: '' },
          { label: '2048x2048', value: '2048x2048' },
          { label: '1440x2880', value: '1440x2880' },
          { label: '2880x1440', value: '2880x1440' },
          { label: '1664x2496', value: '1664x2496' },
          { label: '2496x1664', value: '2496x1664' },
          { label: '1792x2240', value: '1792x2240' },
          { label: '2240x1792', value: '2240x1792' },
          { label: '1440x2560', value: '1440x2560' },
          { label: '2560x1440', value: '2560x1440' },
          { label: '1600x2560', value: '1600x2560' },
          { label: '2560x1600', value: '2560x1600' },
        ],
      },
      {
        key: 'rendering_speed',
        label: 'Rendering Speed',
        type: 'enum',
        required: false,
        default: 'DEFAULT',
        options: [
          { label: 'Turbo', value: 'TURBO' },
          { label: 'Default', value: 'DEFAULT' },
          { label: 'Quality', value: 'QUALITY' },
        ],
      },
    ],
  },

  'ideogram-reframe': {
    id: 'ideogram-reframe',
    displayName: 'Ideogram Reframe (Outpaint)',
    category: 'transform',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/ideogram/v3/reframe',
    envKeyName: ['IDEOGRAM_API_KEY', 'FAL_KEY'],
    executionPattern: 'async-poll',
    directKeyName: 'IDEOGRAM_API_KEY',
    inputPorts: [
      { id: 'image', label: 'Source Image', dataType: 'Image', required: true },
      { id: 'images', label: 'Style Refs', dataType: 'Image', required: false, multiple: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [],
    sharedParams: [
      {
        key: 'num_images',
        label: 'Images',
        type: 'integer',
        required: false,
        default: 1,
        min: 1,
        max: 4,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
    falParams: [
      {
        key: 'image_size',
        label: 'Target Size',
        type: 'enum',
        required: true,
        default: 'square_hd',
        options: [
          { label: 'Square HD', value: 'square_hd' },
          { label: 'Square', value: 'square' },
          { label: 'Portrait 4:3', value: 'portrait_4_3' },
          { label: 'Portrait 16:9', value: 'portrait_16_9' },
          { label: 'Landscape 4:3', value: 'landscape_4_3' },
          { label: 'Landscape 16:9', value: 'landscape_16_9' },
        ],
      },
      {
        key: 'style',
        label: 'Style',
        type: 'enum',
        required: false,
        default: 'AUTO',
        options: [
          { label: 'Auto', value: 'AUTO' },
          { label: 'General', value: 'GENERAL' },
          { label: 'Realistic', value: 'REALISTIC' },
          { label: 'Design', value: 'DESIGN' },
        ],
      },
      {
        key: 'rendering_speed',
        label: 'Rendering Speed',
        type: 'enum',
        required: false,
        default: 'BALANCED',
        options: [
          { label: 'Turbo', value: 'TURBO' },
          { label: 'Balanced', value: 'BALANCED' },
          { label: 'Quality', value: 'QUALITY' },
        ],
      },
    ],
    directParams: [
      {
        key: 'resolution',
        label: 'Target Resolution',
        type: 'enum',
        required: true,
        default: '1024x1024',
        options: [
          { label: '1024x1024', value: '1024x1024' },
          { label: '1280x800', value: '1280x800' },
          { label: '800x1280', value: '800x1280' },
          { label: '1344x768', value: '1344x768' },
          { label: '768x1344', value: '768x1344' },
          { label: '1152x896', value: '1152x896' },
          { label: '896x1152', value: '896x1152' },
          { label: '1216x832', value: '1216x832' },
          { label: '832x1216', value: '832x1216' },
          { label: '1536x640', value: '1536x640' },
        ],
      },
      {
        key: 'rendering_speed',
        label: 'Rendering Speed',
        type: 'enum',
        required: false,
        default: 'DEFAULT',
        options: [
          { label: 'Turbo', value: 'TURBO' },
          { label: 'Default', value: 'DEFAULT' },
          { label: 'Quality', value: 'QUALITY' },
        ],
      },
    ],
  },

  'ideogram-replace-background': {
    id: 'ideogram-replace-background',
    displayName: 'Ideogram Replace Background',
    category: 'image-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/ideogram/v3/replace-background',
    envKeyName: ['IDEOGRAM_API_KEY', 'FAL_KEY'],
    executionPattern: 'async-poll',
    directKeyName: 'IDEOGRAM_API_KEY',
    inputPorts: [
      { id: 'prompt', label: 'New Background', dataType: 'Text', required: true },
      { id: 'image', label: 'Subject Image', dataType: 'Image', required: true },
      { id: 'images', label: 'Style Refs', dataType: 'Image', required: false, multiple: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [],
    sharedParams: [
      {
        key: 'num_images',
        label: 'Images',
        type: 'integer',
        required: false,
        default: 1,
        min: 1,
        max: 4,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
    falParams: [
      {
        key: 'style',
        label: 'Style',
        type: 'enum',
        required: false,
        default: 'AUTO',
        options: [
          { label: 'Auto', value: 'AUTO' },
          { label: 'General', value: 'GENERAL' },
          { label: 'Realistic', value: 'REALISTIC' },
          { label: 'Design', value: 'DESIGN' },
        ],
      },
      {
        key: 'rendering_speed',
        label: 'Rendering Speed',
        type: 'enum',
        required: false,
        default: 'BALANCED',
        options: [
          { label: 'Turbo', value: 'TURBO' },
          { label: 'Balanced', value: 'BALANCED' },
          { label: 'Quality', value: 'QUALITY' },
        ],
      },
      {
        key: 'expand_prompt',
        label: 'Magic Prompt',
        type: 'boolean',
        required: false,
        default: true,
      },
    ],
    directParams: [
      {
        key: 'magic_prompt',
        label: 'Magic Prompt',
        type: 'enum',
        required: false,
        default: 'AUTO',
        options: [
          { label: 'Auto', value: 'AUTO' },
          { label: 'On', value: 'ON' },
          { label: 'Off', value: 'OFF' },
        ],
      },
      {
        key: 'rendering_speed',
        label: 'Rendering Speed',
        type: 'enum',
        required: false,
        default: 'DEFAULT',
        options: [
          { label: 'Turbo', value: 'TURBO' },
          { label: 'Default', value: 'DEFAULT' },
          { label: 'Quality', value: 'QUALITY' },
        ],
      },
    ],
  },

  'ideogram-character': {
    id: 'ideogram-character',
    displayName: 'Ideogram Character',
    category: 'image-gen',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/ideogram/character',
    envKeyName: ['IDEOGRAM_API_KEY', 'FAL_KEY'],
    executionPattern: 'async-poll',
    directKeyName: 'IDEOGRAM_API_KEY',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
      { id: 'character', label: 'Character', dataType: 'Character', required: false },
      { id: 'reference_images', label: 'Character Refs', dataType: 'Image', required: false, multiple: true },
      { id: 'images', label: 'Style Refs', dataType: 'Image', required: false, multiple: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [],
    sharedParams: [
      {
        key: 'negative_prompt',
        label: 'Negative Prompt',
        type: 'string',
        required: false,
        placeholder: 'What to avoid',
      },
      {
        key: 'num_images',
        label: 'Images',
        type: 'integer',
        required: false,
        default: 1,
        min: 1,
        max: 4,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
    falParams: [
      {
        key: 'style',
        label: 'Style',
        type: 'enum',
        required: false,
        default: 'AUTO',
        options: [
          { label: 'Auto', value: 'AUTO' },
          { label: 'Realistic', value: 'REALISTIC' },
          { label: 'Fiction', value: 'FICTION' },
        ],
      },
      {
        key: 'image_size',
        label: 'Size',
        type: 'enum',
        required: false,
        default: 'square_hd',
        options: [
          { label: 'Square HD', value: 'square_hd' },
          { label: 'Square', value: 'square' },
          { label: 'Portrait 4:3', value: 'portrait_4_3' },
          { label: 'Portrait 16:9', value: 'portrait_16_9' },
          { label: 'Landscape 4:3', value: 'landscape_4_3' },
          { label: 'Landscape 16:9', value: 'landscape_16_9' },
        ],
      },
      {
        key: 'rendering_speed',
        label: 'Rendering Speed',
        type: 'enum',
        required: false,
        default: 'BALANCED',
        options: [
          { label: 'Turbo', value: 'TURBO' },
          { label: 'Balanced', value: 'BALANCED' },
          { label: 'Quality', value: 'QUALITY' },
        ],
      },
      {
        key: 'expand_prompt',
        label: 'Magic Prompt',
        type: 'boolean',
        required: false,
        default: true,
      },
    ],
    directParams: [
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: '1x1',
        options: [
          { label: '1:1', value: '1x1' },
          { label: '16:9', value: '16x9' },
          { label: '9:16', value: '9x16' },
          { label: '4:3', value: '4x3' },
          { label: '3:4', value: '3x4' },
          { label: '3:2', value: '3x2' },
          { label: '2:3', value: '2x3' },
          { label: '16:10', value: '16x10' },
          { label: '10:16', value: '10x16' },
          { label: '5:4', value: '5x4' },
          { label: '4:5', value: '4x5' },
          { label: '2:1', value: '2x1' },
          { label: '1:2', value: '1x2' },
          { label: '3:1', value: '3x1' },
          { label: '1:3', value: '1x3' },
        ],
      },
      {
        key: 'style_type',
        label: 'Style Type',
        type: 'enum',
        required: false,
        default: 'AUTO',
        options: [
          { label: 'Auto', value: 'AUTO' },
          { label: 'Realistic', value: 'REALISTIC' },
          { label: 'Fiction', value: 'FICTION' },
        ],
      },
      {
        key: 'magic_prompt',
        label: 'Magic Prompt',
        type: 'enum',
        required: false,
        default: 'AUTO',
        options: [
          { label: 'Auto', value: 'AUTO' },
          { label: 'On', value: 'ON' },
          { label: 'Off', value: 'OFF' },
        ],
      },
      {
        key: 'rendering_speed',
        label: 'Rendering Speed',
        type: 'enum',
        required: false,
        default: 'DEFAULT',
        options: [
          { label: 'Turbo', value: 'TURBO' },
          { label: 'Default', value: 'DEFAULT' },
          { label: 'Quality', value: 'QUALITY' },
        ],
      },
      {
        key: 'custom_model_uri',
        label: 'Custom Model URI',
        type: 'string',
        required: false,
        placeholder: 'From an Ideogram Train Model node',
      },
    ],
  },

  'ideogram-upscale': {
    id: 'ideogram-upscale',
    displayName: 'Ideogram Upscale',
    category: 'transform',
    apiProvider: 'fal',
    apiEndpoint: 'fal-ai/ideogram/upscale',
    envKeyName: ['IDEOGRAM_API_KEY', 'FAL_KEY'],
    executionPattern: 'async-poll',
    directKeyName: 'IDEOGRAM_API_KEY',
    inputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
      { id: 'prompt', label: 'Guidance (optional)', dataType: 'Text', required: false },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [],
    sharedParams: [
      {
        key: 'resemblance',
        label: 'Resemblance',
        type: 'integer',
        required: false,
        default: 50,
        min: 1,
        max: 100,
      },
      {
        key: 'detail',
        label: 'Detail',
        type: 'integer',
        required: false,
        default: 50,
        min: 1,
        max: 100,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
    falParams: [
      {
        key: 'expand_prompt',
        label: 'Magic Prompt',
        type: 'boolean',
        required: false,
        default: false,
      },
    ],
    directParams: [
      {
        key: 'magic_prompt',
        label: 'Magic Prompt',
        type: 'enum',
        required: false,
        default: 'AUTO',
        options: [
          { label: 'Auto', value: 'AUTO' },
          { label: 'On', value: 'ON' },
          { label: 'Off', value: 'OFF' },
        ],
      },
    ],
  },

  'ideogram-describe': {
    id: 'ideogram-describe',
    displayName: 'Ideogram Describe',
    category: 'analyzer',
    apiProvider: 'ideogram',
    apiEndpoint: '/v1/ideogram-v4/describe',
    envKeyName: 'IDEOGRAM_API_KEY',
    executionPattern: 'sync',
    inputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
    ],
    outputPorts: [
      { id: 'description', label: 'Description', dataType: 'Text', required: false },
      { id: 'json_prompt', label: 'JSON Prompt (v4)', dataType: 'Text', required: false },
    ],
    params: [
      {
        key: 'include_bbox',
        label: 'Include Layout (bbox)',
        type: 'boolean',
        required: false,
        default: true,
      },
    ],
  },

  'ideogram-magic-prompt': {
    id: 'ideogram-magic-prompt',
    displayName: 'Ideogram Magic Prompt',
    category: 'text-gen',
    apiProvider: 'ideogram',
    apiEndpoint: '/v1/ideogram-v4/magic-prompt',
    envKeyName: 'IDEOGRAM_API_KEY',
    executionPattern: 'sync',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'description', label: 'Expanded Prompt', dataType: 'Text', required: false },
      { id: 'json_prompt', label: 'JSON Prompt (v4)', dataType: 'Text', required: false },
    ],
    params: [
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: 'AUTO',
        options: [
          { label: 'AUTO', value: 'AUTO' },
          { label: '1:1', value: '1x1' },
          { label: '16:9', value: '16x9' },
          { label: '9:16', value: '9x16' },
          { label: '4:3', value: '4x3' },
          { label: '3:4', value: '3x4' },
          { label: '3:2', value: '3x2' },
          { label: '2:3', value: '2x3' },
          { label: '16:10', value: '16x10' },
          { label: '10:16', value: '10x16' },
          { label: '5:4', value: '5x4' },
          { label: '4:5', value: '4x5' },
          { label: '2:1', value: '2x1' },
          { label: '1:2', value: '1x2' },
          { label: '3:1', value: '3x1' },
          { label: '1:3', value: '1x3' },
          { label: '1:4', value: '1x4' },
          { label: '4:1', value: '4x1' },
        ],
      },
    ],
  },

  'ideogram-transparent': {
    id: 'ideogram-transparent',
    displayName: 'Ideogram Transparent',
    category: 'image-gen',
    apiProvider: 'ideogram',
    apiEndpoint: '/v1/ideogram-v3/generate-transparent',
    envKeyName: 'IDEOGRAM_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Prompt', dataType: 'Text', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image (alpha)', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: '1x1',
        options: [
          { label: '1:1', value: '1x1' },
          { label: '16:9', value: '16x9' },
          { label: '9:16', value: '9x16' },
          { label: '4:3', value: '4x3' },
          { label: '3:4', value: '3x4' },
          { label: '3:2', value: '3x2' },
          { label: '2:3', value: '2x3' },
          { label: '16:10', value: '16x10' },
          { label: '10:16', value: '10x16' },
          { label: '5:4', value: '5x4' },
          { label: '4:5', value: '4x5' },
          { label: '2:1', value: '2x1' },
          { label: '1:2', value: '1x2' },
          { label: '3:1', value: '3x1' },
          { label: '1:3', value: '1x3' },
        ],
      },
      {
        key: 'upscale_factor',
        label: 'Upscale',
        type: 'enum',
        required: false,
        default: 'X1',
        options: [
          { label: '1x', value: 'X1' },
          { label: '2x', value: 'X2' },
          { label: '4x', value: 'X4' },
        ],
      },
      {
        key: 'rendering_speed',
        label: 'Rendering Speed',
        type: 'enum',
        required: false,
        default: 'DEFAULT',
        options: [
          { label: 'Turbo', value: 'TURBO' },
          { label: 'Default', value: 'DEFAULT' },
          { label: 'Quality', value: 'QUALITY' },
        ],
      },
      {
        key: 'magic_prompt',
        label: 'Magic Prompt',
        type: 'enum',
        required: false,
        default: 'AUTO',
        options: [
          { label: 'Auto', value: 'AUTO' },
          { label: 'On', value: 'ON' },
          { label: 'Off', value: 'OFF' },
        ],
      },
      {
        key: 'negative_prompt',
        label: 'Negative Prompt',
        type: 'string',
        required: false,
        placeholder: 'What to avoid',
      },
      {
        key: 'num_images',
        label: 'Images',
        type: 'integer',
        required: false,
        default: 1,
        min: 1,
        max: 4,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
  },

  'ideogram-remove-background': {
    id: 'ideogram-remove-background',
    displayName: 'Ideogram Remove BG',
    category: 'transform',
    apiProvider: 'ideogram',
    apiEndpoint: '/v1/remove-background',
    envKeyName: 'IDEOGRAM_API_KEY',
    executionPattern: 'sync',
    inputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image (alpha)', dataType: 'Image', required: false },
    ],
    params: [],
  },

  'ideogram-layerize': {
    id: 'ideogram-layerize',
    displayName: 'Ideogram Layerize Text',
    category: 'transform',
    apiProvider: 'ideogram',
    apiEndpoint: '/v1/ideogram-v3/layerize-text',
    envKeyName: 'IDEOGRAM_API_KEY',
    executionPattern: 'sync',
    inputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
      { id: 'prompt', label: 'Guidance (optional)', dataType: 'Text', required: false },
    ],
    outputPorts: [
      { id: 'image', label: 'Base Plate (text removed)', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
  },

  'ideogram-edit-prompt': {
    id: 'ideogram-edit-prompt',
    displayName: 'Ideogram Edit (Prompt)',
    category: 'image-gen',
    apiProvider: 'ideogram',
    apiEndpoint: '/v1/edit',
    envKeyName: 'IDEOGRAM_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'prompt', label: 'Edit Instruction', dataType: 'Text', required: true },
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
      { id: 'images', label: 'Images', dataType: 'Image', required: false, multiple: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'magic_prompt',
        label: 'Magic Prompt',
        type: 'enum',
        required: false,
        default: 'AUTO',
        options: [
          { label: 'Auto', value: 'AUTO' },
          { label: 'On', value: 'ON' },
          { label: 'Off', value: 'OFF' },
        ],
      },
      {
        key: 'aspect_ratio',
        label: 'Aspect Ratio',
        type: 'enum',
        required: false,
        default: '',
        options: [
          { label: 'Keep input', value: '' },
          { label: '1:1', value: '1x1' },
          { label: '16:9', value: '16x9' },
          { label: '9:16', value: '9x16' },
          { label: '4:3', value: '4x3' },
          { label: '3:4', value: '3x4' },
          { label: '3:2', value: '3x2' },
          { label: '2:3', value: '2x3' },
          { label: '16:10', value: '16x10' },
          { label: '10:16', value: '10x16' },
          { label: '5:4', value: '5x4' },
          { label: '4:5', value: '4x5' },
          { label: '2:1', value: '2x1' },
          { label: '1:2', value: '1x2' },
          { label: '3:1', value: '3x1' },
          { label: '1:3', value: '1x3' },
        ],
      },
      {
        key: 'transparent_background',
        label: 'Transparent Background',
        type: 'boolean',
        required: false,
        default: false,
      },
      {
        key: 'num_images',
        label: 'Images',
        type: 'integer',
        required: false,
        default: 1,
        min: 1,
        max: 4,
      },
      {
        key: 'seed',
        label: 'Seed',
        type: 'integer',
        required: false,
        placeholder: 'Random',
      },
    ],
  },

  'ideogram-train-model': {
    id: 'ideogram-train-model',
    displayName: 'Ideogram Train Model',
    category: 'image-gen',
    apiProvider: 'ideogram',
    apiEndpoint: '/v1/ideogram-v3/train-model',
    envKeyName: 'IDEOGRAM_API_KEY',
    executionPattern: 'async-poll',
    inputPorts: [
      { id: 'images', label: 'Training Images', dataType: 'Image', required: true, multiple: true },
    ],
    outputPorts: [
      { id: 'custom_model_uri', label: 'Custom Model URI', dataType: 'Text', required: false },
      { id: 'model_id', label: 'Model ID', dataType: 'Text', required: false },
    ],
    params: [
      {
        key: 'model_name',
        label: 'Model Name',
        type: 'string',
        required: true,
        placeholder: 'my-brand-style',
      },
    ],
  },

  'mask-painter': {
    id: 'mask-painter',
    displayName: 'Mask Painter',
    category: 'utility',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    inputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: true },
    ],
    outputPorts: [
      { id: 'mask', label: 'Mask', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'polarity',
        label: 'Painted Area Means',
        type: 'enum',
        required: false,
        default: 'white-edit',
        options: [
          { label: 'White = edit (FLUX Fill)', value: 'white-edit' },
          { label: 'Black = edit (Ideogram)', value: 'black-edit' },
        ],
      },
    ],
  },

  'svg-rasterize': {
    id: 'svg-rasterize',
    displayName: 'SVG Rasterize',
    category: 'transform',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    inputPorts: [
      { id: 'svg', label: 'SVG', dataType: 'SVG', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'width',
        label: 'Width',
        type: 'integer',
        required: false,
        default: 1024,
        min: 64,
        max: 4096,
      },
      {
        key: 'height',
        label: 'Height',
        type: 'integer',
        required: false,
        default: 1024,
        min: 64,
        max: 4096,
      },
      {
        key: 'background',
        label: 'Background',
        type: 'enum',
        required: false,
        default: 'transparent',
        options: [
          { label: 'Transparent', value: 'transparent' },
          { label: 'White', value: 'white' },
        ],
      },
    ],
  },

  'iterator-image': {
    id: 'iterator-image',
    displayName: 'Image Iterator',
    category: 'utility',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    inputPorts: [
      { id: 'array', label: 'Images', dataType: 'Array', required: true },
    ],
    outputPorts: [
      { id: 'image', label: 'Image', dataType: 'Image', required: false },
    ],
    params: [
      {
        key: 'batch_size_cap',
        label: 'Batch Size Cap',
        type: 'integer',
        required: false,
        default: 10,
        min: 1,
        max: 25,
      },
    ],
  },

  'iterator-text': {
    id: 'iterator-text',
    displayName: 'Text Iterator',
    category: 'utility',
    apiProvider: 'utility',
    apiEndpoint: '',
    envKeyName: [],
    executionPattern: 'sync',
    inputPorts: [
      { id: 'array', label: 'Texts', dataType: 'Array', required: true },
    ],
    outputPorts: [
      { id: 'text', label: 'Text', dataType: 'Text', required: false },
    ],
    params: [
      {
        key: 'batch_size_cap',
        label: 'Batch Size Cap',
        type: 'integer',
        required: false,
        default: 10,
        min: 1,
        max: 25,
      },
    ],
  },
};

export function getNodeDefinition(definitionId: string): ModelNodeDefinition | undefined {
  return NODE_DEFINITIONS[definitionId];
}

// Display order for categories in the node library panel. Categories not listed
// here fall to the bottom in the order they're first encountered.
const CATEGORY_ORDER: readonly string[] = [
  'utility',
  'cinematic',
  'character',
  'text-gen',
  'image-gen',
  'video-gen',
  'audio-gen',
  'transform',
  'analyzer',
  'universal',
];

export function getNodesByCategory(): Record<string, ModelNodeDefinition[]> {
  const grouped: Record<string, ModelNodeDefinition[]> = {};
  for (const def of Object.values(NODE_DEFINITIONS)) {
    if (!grouped[def.category]) {
      grouped[def.category] = [];
    }
    grouped[def.category].push(def);
  }
  // Rebuild the object so Object.entries iterates in CATEGORY_ORDER.
  const ordered: Record<string, ModelNodeDefinition[]> = {};
  for (const cat of CATEGORY_ORDER) {
    if (grouped[cat]) ordered[cat] = grouped[cat];
  }
  for (const [cat, defs] of Object.entries(grouped)) {
    if (!(cat in ordered)) ordered[cat] = defs;
  }
  return ordered;
}
