Advertisement

← vibesdk

worker/agents/inferutils/config.types.ts

15.2 KB Download file
/**
 * Config Types - Pure type definitions only
 */

export type ReasoningEffortType = 'minimal' | 'low' | 'medium' | 'high';
export type ReasoningEffort = ReasoningEffortType;

export enum ModelSize {
    LITE = 'lite',
    REGULAR = 'regular',
    LARGE = 'large',
}

export interface AIModelConfig {
    name: string;
    size: ModelSize;
    provider: string;
    creditCost: number;
    contextSize: number;
    nonReasoning?: boolean;
    directOverride?: boolean;
}

// Pricing Baseline: GPT-5 Mini ($0.25/1M Input) = 1.0 Credit
const MODELS_MASTER = {
    DISABLED: {
        id: 'disabled',
        config: {
            name: 'Disabled',
            size: ModelSize.LITE,
            provider: 'None',
            creditCost: 0,
            contextSize: 0,
        }
    },
    // --- Google Models ---
    GEMINI_2_5_PRO: {
        id: 'google-ai-studio/gemini-2.5-pro',
        config: {
            name: 'Gemini 2.5 Pro',
            size: ModelSize.LARGE,
            provider: 'google-ai-studio',
            creditCost: 5,   // $1.25
            contextSize: 1048576, // 1M Context
        }
    },
    GEMINI_2_5_FLASH: {
        id: 'google-ai-studio/gemini-2.5-flash',
        config: {
            name: 'Gemini 2.5 Flash',
            size: ModelSize.REGULAR,
            provider: 'google-ai-studio',
            creditCost: 1.2, // $0.30
            contextSize: 1048576, // 1M Context
        }
    },
    GEMINI_2_5_FLASH_LITE: {
        id: 'google-ai-studio/gemini-2.5-flash-lite',
        config: {
            name: 'Gemini 2.5 Flash-Lite',
            size: ModelSize.LITE,
            provider: 'google-ai-studio',
            creditCost: 0.4, // $0.10
            contextSize: 1048576, // 1M Context
        }
    },
    GEMINI_2_5_FLASH_LATEST: {
        id: 'google-ai-studio/gemini-2.5-flash-latest',
        config: {
            name: 'Gemini 2.5 Flash (Latest)',
            size: ModelSize.REGULAR,
            provider: 'google-ai-studio',
            creditCost: 1.2, // $0.30
            contextSize: 1048576,
        }
    },
    GEMINI_2_5_FLASH_LITE_LATEST: {
        id: 'google-ai-studio/gemini-2.5-flash-lite-latest',
        config: {
            name: 'Gemini 2.5 Flash-Lite (Latest)',
            size: ModelSize.LITE,
            provider: 'google-ai-studio',
            creditCost: 0.4, // $0.10
            contextSize: 1048576,
        }
    },
    GEMINI_2_5_PRO_LATEST: {
        id: 'google-ai-studio/gemini-2.5-pro-latest',
        config: {
            name: 'Gemini 2.5 Pro (Latest)',
            size: ModelSize.LARGE,
            provider: 'google-ai-studio',
            creditCost: 5, // $1.25
            contextSize: 1048576,
        }
    },
    GEMINI_3_PRO_PREVIEW: {
        id: 'google-ai-studio/gemini-3-pro-preview',
        config: {
            name: 'Gemini 3.0 Pro Preview',
            size: ModelSize.LARGE,
            provider: 'google-ai-studio',
            creditCost: 8, // $2.00 (Preview Pricing)
            contextSize: 1048576,
        }
    },
    GEMINI_3_FLASH_PREVIEW: {
        id: 'google-ai-studio/gemini-3-flash-preview',
        config: {
            name: 'Gemini 3.0 Flash Preview',
            size: ModelSize.REGULAR,
            provider: 'google-ai-studio',
            creditCost: 2, // $0.5
            contextSize: 1048576, // 1M Context
        }
    },

    // --- Anthropic Models ---
    CLAUDE_3_7_SONNET_20250219: {
        id: 'anthropic/claude-3-7-sonnet-20250219',
        config: {
            name: 'Claude 3.7 Sonnet',
            size: ModelSize.LARGE,
            provider: 'anthropic',
            creditCost: 12, // $3.00
            contextSize: 200000, // 200K Context
        }
    },
    CLAUDE_4_SONNET: {
        id: 'anthropic/claude-sonnet-4-20250514',
        config: {
            name: 'Claude 4 Sonnet',
            size: ModelSize.LARGE,
            provider: 'anthropic',
            creditCost: 12, // $3.00
            contextSize: 200000, // 200K Context
        }
    },
    CLAUDE_4_5_SONNET: {
        id: 'anthropic/claude-sonnet-4-5',
        config: {
            name: 'Claude 4.5 Sonnet',
            size: ModelSize.LARGE,
            provider: 'anthropic',
            creditCost: 12, // $3.00
            contextSize: 200000, // 200K Context
        }
    },
    CLAUDE_4_5_OPUS: {
        id: 'anthropic/claude-opus-4-5',
        config: {
            name: 'Claude 4.5 Opus',
            size: ModelSize.LARGE,
            provider: 'anthropic',
            creditCost: 20, // $5.00
            contextSize: 200000, // 200K Context
        }
    },
    CLAUDE_4_5_HAIKU: {
        id: 'anthropic/claude-haiku-4-5',
        config: {
            name: 'Claude 4.5 Haiku',
            size: ModelSize.REGULAR,
            provider: 'anthropic',
            creditCost: 4, // ~$1
            contextSize: 200000, // 200K Context
        }
    },

    // --- OpenAI Models ---
    OPENAI_5: {
        id: 'openai/gpt-5',
        config: {
            name: 'GPT-5',
            size: ModelSize.LARGE,
            provider: 'openai',
            creditCost: 5, // $1.25
            contextSize: 400000, // 400K Context
        }
    },
    OPENAI_5_1: {
        id: 'openai/gpt-5.1',
        config: {
            name: 'GPT-5.1',
            size: ModelSize.LARGE,
            provider: 'openai',
            creditCost: 5, // $1.25
            contextSize: 400000, // 400K Context
        }
    },
    OPENAI_5_2: {
        id: 'openai/gpt-5.2',
        config: {
            name: 'GPT-5.2',
            size: ModelSize.LARGE,
            provider: 'openai',
            creditCost: 7, // $1.75
            contextSize: 400000, // 400K Context
        }
    },
    OPENAI_5_MINI: {
        id: 'openai/gpt-5-mini',
        config: {
            name: 'GPT-5 Mini',
            size: ModelSize.LITE,
            provider: 'openai',
            creditCost: 1, // $0.25 (BASELINE)
            contextSize: 400000, // 400K Context
        }
    },
    // Below configs are commented for now, may be supported in the future
    // OPENAI_OSS: {
    //     id: 'openai/gpt-oss-120b',
    //     config: {
    //         name: 'GPT-OSS 120b',
    //         size: ModelSize.LITE,
    //         provider: 'openai',
    //         creditCost: 0.4,
    //         contextSize: 131072, // 128K Context
    //     }
    // },
    // OPENAI_5_1_CODEX_MINI: {
    //     id: 'openai/gpt-5.1-codex-mini',
    //     config: {
    //         name: 'GPT-5.1 Codex Mini',
    //         size: ModelSize.LITE,
    //         provider: 'openai',
    //         creditCost: 1, // ~$0.25
    //         contextSize: 400000, // 400K Context
    //     }
    // },
    // OPENAI_5_1_CODEX: {
    //     id: 'openai/gpt-5.1-codex',
    //     config: {
    //         name: 'GPT-5.1 Codex',
    //         size: ModelSize.LARGE,
    //         provider: 'openai',
    //         creditCost: 5, // ~$1.25
    //         contextSize: 400000, // 400K Context
    //     }
    // },

    // // --- Cerebras Models ---
    // CEREBRAS_GPT_OSS: {
    //     id: 'cerebras/gpt-oss-120b',
    //     config: {
    //         name: 'Cerebras GPT-OSS',
    //         size: ModelSize.LITE,
    //         provider: 'Cerebras',
    //         creditCost: 0.4, // $0.25
    //         contextSize: 131072, // 128K Context
    //     }
    // },
    // CEREBRAS_QWEN_3_CODER: {
    //     id: 'cerebras/qwen-3-coder-480b',
    //     config: {
    //         name: 'Qwen 3 Coder',
    //         size: ModelSize.REGULAR,
    //         provider: 'cerebras',
    //         creditCost: 4, // Est ~$1.00 for 480B param
    //         contextSize: 32768,
    //     }
    // },

    // --- Grok Models ---
    GROK_CODE_FAST_1: {
        id: 'grok/grok-code-fast-1',
        config: {
            name: 'Grok Code Fast 1',
            size: ModelSize.LITE,
            provider: 'grok',
            creditCost: 0.8, // $0.20
            contextSize: 256000, // 256K Context
            nonReasoning: true,
        }
    },
    GROK_4_FAST: {
        id: 'grok/grok-4-fast',
        config: {
            name: 'Grok 4 Fast',
            size: ModelSize.LITE,
            provider: 'grok',
            creditCost: 0.8, // $0.20
            contextSize: 2_000_000, // 2M Context
            nonReasoning: true,
        }
    },
    GROK_4_1_FAST: {
        id: 'grok/grok-4-1-fast-reasoning',
        config: {
            name: 'Grok 4.1 Fast',
            size: ModelSize.LITE,
            provider: 'grok',
            creditCost: 0.8, // $0.20
            contextSize: 2_000_000, // 2M Context
            nonReasoning: true,
        }
    },
    GROK_4_1_FAST_NON_REASONING: {
        id: 'grok/grok-4-1-fast-non-reasoning',
        config: {
            name: 'Grok 4.1 Fast Non reasoning',
            size: ModelSize.LITE,
            provider: 'grok',
            creditCost: 0.8, // $0.20
            contextSize: 2_000_000, // 2M Context
            nonReasoning: true,
        }
    },
    // --- Vertex Models ---
    VERTEX_GPT_OSS_120: {
        id: 'google-vertex-ai/openai/gpt-oss-120b-maas',
        config: {
            name: 'Google Vertex GPT OSS 120B',
            size: ModelSize.LITE,
            provider: 'google-vertex-ai',
            creditCost: 0.36, // $0.09
            contextSize: 131072, // 128K Context
        }
    },
    VERTEX_KIMI_THINKING: {
        id: 'google-vertex-ai/moonshotai/kimi-k2-thinking-maas',
        config: {
            name: 'Google Vertex Kimi K2 Thinking',
            size: ModelSize.LITE,
            provider: 'google-vertex-ai',
            creditCost: 2, // $0.50
            contextSize: 262144, // 256K Context
        }
    },
    QWEN_3_CODER_480B: {
        id: 'google-vertex-ai/qwen/qwen3-coder-480b-a35b-instruct-maas',
        config: {
            name: 'Qwen 3 Coder 480B',
            size: ModelSize.LITE,
            provider: 'google-vertex-ai',
            creditCost: 8, // $0.22
            contextSize: 262144, // 256K Context
        },
    }
} as const;

/**
 * Generated AIModels object
 */
export const AIModels = Object.fromEntries(
    Object.entries(MODELS_MASTER).map(([key, value]) => [key, value.id])
) as { [K in keyof typeof MODELS_MASTER]: typeof MODELS_MASTER[K]['id'] };

/**
 * Type definition for AIModels values.
 */
export type AIModels = typeof AIModels[keyof typeof AIModels];

/**
 * Configuration map for all AI Models.
 * Usage: AI_MODEL_CONFIG[AIModels.GEMINI_2_5_PRO]
 */
export const AI_MODEL_CONFIG: Record<AIModels, AIModelConfig> = Object.fromEntries(
    Object.values(MODELS_MASTER).map((entry) => [entry.id, entry.config])
) as Record<AIModels, AIModelConfig>;

/**
 * Dynamically generated list of Lite models based on ModelSize.LITE
 */
export const LiteModels: AIModels[] = Object.values(MODELS_MASTER)
    .filter((entry) => entry.config.size === ModelSize.LITE)
    .map((entry) => entry.id);

export const RegularModels: AIModels[] = Object.values(MODELS_MASTER)
    .filter((entry) => entry.config.size === ModelSize.REGULAR || entry.config.size === ModelSize.LITE)
    .map((entry) => entry.id);

export const AllModels: AIModels[] = Object.values(MODELS_MASTER)
    .map((entry) => entry.id);

export interface AgentConstraintConfig {
    allowedModels: Set<AIModels>;
    enabled: boolean;
}

export interface AgentConstraintConfig {
    allowedModels: Set<AIModels>;
    enabled: boolean;
}

export interface ModelConfig {
    name: AIModels | string;
    reasoning_effort?: ReasoningEffort;
    max_tokens?: number;
    temperature?: number;
    frequency_penalty?: number;
    fallbackModel?: AIModels | string;
}

export interface AgentConfig {
    templateSelection: ModelConfig;
    blueprint: ModelConfig;
    projectSetup: ModelConfig;
    phaseGeneration: ModelConfig;
    phaseImplementation: ModelConfig;
    firstPhaseImplementation: ModelConfig;
    fileRegeneration: ModelConfig;
    screenshotAnalysis: ModelConfig;
    realtimeCodeFixer: ModelConfig;
    fastCodeFixer: ModelConfig;
    conversationalResponse: ModelConfig;
    deepDebugger: ModelConfig;
    agenticProjectBuilder: ModelConfig;
}

// Provider and reasoning effort types for validation
export type ProviderOverrideType = 'cloudflare' | 'direct';

export type AgentActionKey = keyof AgentConfig;

/**
 * Metadata used in agent for inference and other tasks
 */
export type InferenceMetadata = {
    agentId: string;
    userId: string;
    // llmRateLimits: LLMCallsRateLimitConfig;
}

export type InferenceRuntimeOverrides = {
	/** Provider API keys (BYOK) keyed by provider id, e.g. "openai" -> key. */
	userApiKeys?: Record<string, string>;
	/** Optional AI gateway override (baseUrl + token). */
	aiGatewayOverride?: { baseUrl: string; token: string };
};

/**
 * Runtime-only overrides used for inference.
 * This is never persisted in Durable Object state.
 */
export interface InferenceContext {
    metadata: InferenceMetadata;
    enableRealtimeCodeFix: boolean;
    enableFastSmartCodeFix: boolean;
    abortSignal?: AbortSignal;
    userModelConfigs?: Record<AgentActionKey, ModelConfig>;
    runtimeOverrides?: InferenceRuntimeOverrides;
    shouldUseUserKey?: boolean; // Set once at request start based on limit check
    userApiToken?: string | null; // Encrypted Cloudflare OAuth token blob read server-side from the HttpOnly cookie (or captured at WS upgrade time) and decrypted by the backend; never sent as a client header.
    userGateway?: { // User's AI Gateway for BYOK
        accountId: string;
        gatewaySlug: string;
    } | null;
    onUsageConsumed?: () => void; // Called after each LLM call consumes credits
}

/**
 * SDK-facing credential payload
 */
export type CredentialsPayload = {
	providers?: Record<string, { apiKey: string }>;
	aiGateway?: { baseUrl: string; token: string };
};

/**
 * Validates a user-supplied AI gateway baseUrl. Requires a well-formed
 * absolute https URL. Returns false for malformed or non-https values so the
 * override is dropped rather than plumbed downstream.
 */
function isValidGatewayBaseUrl(baseUrl: string | undefined): boolean {
	if (!baseUrl) return false;
	try {
		return new URL(baseUrl).protocol === 'https:';
	} catch {
		return false;
	}
}

export function credentialsToRuntimeOverrides(
	credentials: CredentialsPayload | undefined,
): InferenceRuntimeOverrides | undefined {
	if (!credentials) return undefined;

	const userApiKeys: Record<string, string> = {};
	for (const [provider, v] of Object.entries(credentials.providers ?? {})) {
		if (v.apiKey) userApiKeys[provider] = v.apiKey;
	}

	const hasKeys = Object.keys(userApiKeys).length > 0;
	const hasValidGateway =
		!!credentials.aiGateway && isValidGatewayBaseUrl(credentials.aiGateway.baseUrl);
	return {
		...(hasKeys ? { userApiKeys } : {}),
		...(hasValidGateway ? { aiGatewayOverride: credentials.aiGateway } : {}),
	};
}

export function isValidAIModel(value: string): value is AIModels {
  return Object.values(AIModels).includes(value as AIModels);
}

export function toAIModel(value: string | null | undefined): AIModels | undefined {
  if (!value) return undefined;
  return isValidAIModel(value) ? value : undefined;
}