// ST-BME: 任务级生成参数过滤层(Phase 1) import { getActiveTaskProfile } from "../prompting/prompt-profiles.js"; const SUPPORTED_FIELDS = [ "max_context_tokens", "max_completion_tokens", "reply_count", "stream", "temperature", "top_p", "top_k", "top_a", "min_p", "seed", "frequency_penalty", "presence_penalty", "repetition_penalty", "squash_system_messages", "reasoning_effort", "request_thoughts", "enable_function_calling", "enable_web_search", "character_name_prefix", "wrap_user_messages_in_quotes", ]; const CONSERVATIVE_ALLOWLIST = new Set([ "temperature", "top_p", "seed", "max_completion_tokens", "stream", "frequency_penalty", "presence_penalty", ]); const OPENAI_COMPAT_ALLOWLIST = new Set([ "max_completion_tokens", "stream", "temperature", "top_p", "seed", "frequency_penalty", "presence_penalty", "reasoning_effort", "request_thoughts", "enable_function_calling", "enable_web_search", "wrap_user_messages_in_quotes", ]); const BOOLEAN_FIELDS = new Set([ "stream", "squash_system_messages", "request_thoughts", "enable_function_calling", "enable_web_search", "wrap_user_messages_in_quotes", ]); const INTEGER_FIELDS = new Set([ "max_context_tokens", "max_completion_tokens", "reply_count", "top_k", "seed", ]); const FLOAT_FIELDS = new Set([ "temperature", "top_p", "top_a", "min_p", "frequency_penalty", "presence_penalty", "repetition_penalty", ]); const REASONING_EFFORT_VALUES = new Set(["low", "medium", "high", "minimal"]); function resolveCapabilityMode(context = {}) { const normalizedMode = String(context.mode || "").trim().toLowerCase(); if (normalizedMode === "dedicated-openai-compatible") { return "openai-compatible"; } const normalizedSource = String(context.source || "").trim().toLowerCase(); if ( normalizedSource && ["openai", "openrouter", "mistral", "cohere", "custom", "vllm"].includes( normalizedSource, ) ) { return "openai-compatible"; } return "conservative"; } function getAllowlistForCapability(capabilityMode) { if (capabilityMode === "openai-compatible") { return OPENAI_COMPAT_ALLOWLIST; } return CONSERVATIVE_ALLOWLIST; } function normalizeByField(field, rawValue) { if (rawValue == null || rawValue === "") { return { ok: false, reason: "empty_value" }; } if (BOOLEAN_FIELDS.has(field)) { return { ok: true, value: Boolean(rawValue) }; } if (INTEGER_FIELDS.has(field)) { const parsed = Number.parseInt(rawValue, 10); if (!Number.isFinite(parsed)) { return { ok: false, reason: "invalid_number" }; } if (parsed < 0) { return { ok: false, reason: "invalid_range" }; } if (field === "reply_count" && parsed < 1) { return { ok: false, reason: "invalid_range" }; } return { ok: true, value: parsed }; } if (FLOAT_FIELDS.has(field)) { const parsed = Number.parseFloat(rawValue); if (!Number.isFinite(parsed)) { return { ok: false, reason: "invalid_number" }; } if (field === "temperature" && (parsed < 0 || parsed > 2)) { return { ok: false, reason: "invalid_range" }; } if ( ["top_p", "top_a", "min_p"].includes(field) && (parsed < 0 || parsed > 1) ) { return { ok: false, reason: "invalid_range" }; } if ( ["frequency_penalty", "presence_penalty", "repetition_penalty"].includes( field, ) && (parsed < -2 || parsed > 2) ) { return { ok: false, reason: "invalid_range" }; } return { ok: true, value: parsed }; } if (field === "reasoning_effort") { const normalized = String(rawValue || "") .trim() .toLowerCase(); if (!normalized) { return { ok: false, reason: "empty_value" }; } if (!REASONING_EFFORT_VALUES.has(normalized)) { return { ok: false, reason: "invalid_value" }; } return { ok: true, value: normalized }; } if (field === "character_name_prefix") { return { ok: true, value: String(rawValue || "").trim() }; } return { ok: true, value: rawValue }; } export function resolveTaskGenerationOptions( settings = {}, taskType, fallback = {}, capabilityContext = {}, ) { const profile = getActiveTaskProfile(settings, taskType); const generation = { ...(profile?.generation || {}) }; const filtered = {}; const removed = []; const capabilityMode = resolveCapabilityMode(capabilityContext); const allowlist = getAllowlistForCapability(capabilityMode); for (const field of SUPPORTED_FIELDS) { if (!Object.prototype.hasOwnProperty.call(generation, field)) continue; const rawValue = generation[field]; if (rawValue == null || rawValue === "") continue; if (!allowlist.has(field)) { removed.push({ field, reason: "capability_filtered", capabilityMode }); continue; } const normalized = normalizeByField(field, rawValue); if (!normalized.ok) { removed.push({ field, reason: normalized.reason, capabilityMode }); continue; } filtered[field] = normalized.value; } if (!Number.isFinite(filtered.max_completion_tokens)) { const fallbackTokens = Number.parseInt(fallback.max_completion_tokens, 10); if (Number.isFinite(fallbackTokens) && fallbackTokens > 0) { filtered.max_completion_tokens = fallbackTokens; } } return { profile, generation, filtered, removed, capabilityMode, }; }