UNPKG

@lobehub/chat

Version:

Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.

277 lines (258 loc) • 7.53 kB
/** * Chat completion parameter configuration */ interface ParameterConfig { /** * Frequency penalty (reduces repetition) */ frequency_penalty?: number; /** * Maximum tokens to generate */ max_tokens?: number; /** * Presence penalty (reduces topic repetition) */ presence_penalty?: number; /** * Temperature value (0-2 range, controls randomness) */ temperature?: number; /** * Top P value (0-1 range, nucleus sampling) */ top_p?: number; } /** * Range constraint for a numeric parameter */ interface RangeConstraint { max?: number; min?: number; } /** * Parameter resolver options for model-specific constraints */ interface ParameterResolverOptions { /** * Frequency penalty range constraints */ frequencyPenaltyRange?: RangeConstraint; /** * Whether the model has a conflict between temperature and top_p * If true, only one parameter can be set * @default false */ hasConflict?: boolean; /** * Max tokens range constraints */ maxTokensRange?: RangeConstraint; /** * Whether to normalize temperature (divide by 2) * @default true */ normalizeTemperature?: boolean; /** * Whether to prefer temperature over top_p when both are set and there's a conflict * @default true */ preferTemperature?: boolean; /** * Presence penalty range constraints */ presencePenaltyRange?: RangeConstraint; /** * Temperature value range constraints */ temperatureRange?: RangeConstraint; /** * Top P value range constraints */ topPRange?: RangeConstraint; } /** * Resolved parameters ready for API calls */ interface ResolvedParameters { frequency_penalty?: number; max_tokens?: number; presence_penalty?: number; temperature?: number; top_p?: number; } /** * Apply range constraints to a numeric value */ const applyRangeConstraint = ( value: number | undefined, range: RangeConstraint | undefined, ): number | undefined => { if (value === undefined || !range) return value; let result = value; if (range.min !== undefined) { result = Math.max(range.min, result); } if (range.max !== undefined) { result = Math.min(range.max, result); } return result; }; /** * Resolves and normalizes chat completion parameters based on model constraints * * This is a core utility for handling model-specific parameter requirements: * - Parameter conflicts (e.g., Claude 4+ doesn't allow both temperature and top_p) * - Value normalization (e.g., temperature / 2 for some models) * - Range constraints (e.g., min/max values) * * @param config - The input parameter values * @param options - Resolution options including conflict handling and normalization rules * @returns Resolved parameters with only valid values * * @example * // Basic usage with conflict (Claude Opus 4.1) * resolveParameters( * { temperature: 1, top_p: 0.9 }, * { hasConflict: true, preferTemperature: true } * ) * // Returns: { temperature: 0.5 } // temperature normalized and top_p omitted * * @example * // Without conflict * resolveParameters( * { temperature: 1, top_p: 0.9 }, * { hasConflict: false } * ) * // Returns: { temperature: 0.5, top_p: 0.9 } * * @example * // With range constraints (Zhipu glm-4-alltools) * resolveParameters( * { temperature: 1, top_p: 0.5 }, * { * normalizeTemperature: true, * temperatureRange: { min: 0.01, max: 0.99 }, * topPRange: { min: 0.01, max: 0.99 } * } * ) * // Returns: { temperature: 0.5, top_p: 0.5 } * * @example * // With multiple parameters (Qwen) * resolveParameters( * { temperature: 1.5, top_p: 0.8, presence_penalty: 1.5 }, * { * normalizeTemperature: false, * temperatureRange: { min: 0, max: 2 }, * topPRange: { min: 0, max: 1 }, * presencePenaltyRange: { min: -2, max: 2 } * } * ) * // Returns: { temperature: 1.5, top_p: 0.8, presence_penalty: 1.5 } */ export const resolveParameters = ( config: ParameterConfig, options: ParameterResolverOptions = {}, ): ResolvedParameters => { const { hasConflict = false, preferTemperature = true, normalizeTemperature = true, temperatureRange, topPRange, frequencyPenaltyRange, presencePenaltyRange, maxTokensRange, } = options; const { temperature, top_p, frequency_penalty, presence_penalty, max_tokens } = config; const result: ResolvedParameters = {}; // Determine which parameters are provided const shouldSetTemperature = temperature !== undefined; const shouldSetTopP = top_p !== undefined; // Handle temperature and top_p conflict if (hasConflict) { if (preferTemperature && shouldSetTemperature) { // Set temperature only let finalTemp = normalizeTemperature && temperature !== undefined ? temperature / 2 : temperature; result.temperature = applyRangeConstraint(finalTemp, temperatureRange); } else if (shouldSetTopP) { // Set top_p only result.top_p = applyRangeConstraint(top_p, topPRange); } } else { // No conflict: set both parameters if provided if (shouldSetTemperature) { let finalTemp = normalizeTemperature && temperature !== undefined ? temperature / 2 : temperature; result.temperature = applyRangeConstraint(finalTemp, temperatureRange); } if (shouldSetTopP) { result.top_p = applyRangeConstraint(top_p, topPRange); } } // Handle other parameters (no conflicts) if (frequency_penalty !== undefined) { result.frequency_penalty = applyRangeConstraint(frequency_penalty, frequencyPenaltyRange); } if (presence_penalty !== undefined) { result.presence_penalty = applyRangeConstraint(presence_penalty, presencePenaltyRange); } if (max_tokens !== undefined) { result.max_tokens = applyRangeConstraint(max_tokens, maxTokensRange); } return result; }; /** * Creates a parameter resolver with predefined model-specific rules * * @example * // Create a resolver for Claude Opus 4.1 * const claudeOpusResolver = createParameterResolver({ * hasConflict: true, * preferTemperature: true, * normalizeTemperature: true * }); * * const params = claudeOpusResolver({ temperature: 1, top_p: 0.9 }); * // Returns: { temperature: 0.5 } */ export const createParameterResolver = (options: ParameterResolverOptions) => { return (config: ParameterConfig): ResolvedParameters => { return resolveParameters(config, options); }; }; /** * Common model sets that have parameter conflicts */ export const MODEL_PARAMETER_CONFLICTS = { /** * Claude models after Opus 4.1 that don't allow both temperature and top_p */ ANTHROPIC_CLAUDE_4_PLUS: new Set([ 'claude-opus-4-1', 'claude-opus-4-1-20250805', 'claude-sonnet-4-5-20250929', 'claude-haiku-4-5-20251001', ]), /** * Bedrock Claude 4+ models (including Bedrock-specific model IDs) */ BEDROCK_CLAUDE_4_PLUS: new Set([ 'claude-opus-4-1', 'claude-opus-4-1-20250805', 'claude-opus-4-20250514', 'claude-sonnet-4-20250514', 'claude-sonnet-4-5-20250929', // Bedrock model IDs 'anthropic.claude-opus-4-1-20250805-v1:0', 'us.anthropic.claude-opus-4-1-20250805-v1:0', 'anthropic.claude-opus-4-20250514-v1:0', 'us.anthropic.claude-opus-4-20250514-v1:0', 'anthropic.claude-sonnet-4-20250514-v1:0', 'us.anthropic.claude-sonnet-4-20250514-v1:0', 'anthropic.claude-sonnet-4-5-20250929-v1:0', 'us.anthropic.claude-sonnet-4-5-20250929-v1:0', ]), };