Runtime IA: modelo dinámico, razonamiento, coste por modelo y visión nativa
- Resolución dinámica del modelo por sesión (model_resolver): override de usuario (metadata) → default global (Redis db 0 acai:config:ai:*) → fallback. Mapea a string litellm; LiteLLMAdapter respeta el modelo por request y enruta openrouter/* con OPENROUTER_API_KEY del entorno. - Razonamiento: reasoning_effort por sesión en ModelConfig/AgentProfile, aplicado al agente y al planner. - Coste: cost.py calcula por modelo (catálogo OpenRouter/DeepSeek en Redis → litellm → fijo) y emite tarifas + modelo usado en EXECUTION_COMPLETED. - Visión nativa: imágenes como bloques image_url en el turno del usuario (TaskState.image_attachments → Context Engine → adapter), con persistencia en recent_messages y conteo de tokens de imagen (~1500). - El turno no se pierde al cancelar: se persiste el mensaje del usuario + marca de interrupción para que un "vuelve a intentarlo" tenga contexto. - Fix analyze_image: preservar el subdirectorio de usuario del chat-upload (basename descartaba "<user>/" → not found). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -57,11 +57,16 @@ function resolveChatPreviewPath(imageUrl) {
|
||||
const fileParam = qs.get("file");
|
||||
if (!fileParam) return null;
|
||||
|
||||
// Sanitizar: evitar traversal — solo nombre base permitido
|
||||
const safeName = path.basename(fileParam);
|
||||
if (!safeName || safeName === "." || safeName === "..") return null;
|
||||
// Sanitizar contra traversal PRESERVANDO el subdirectorio de usuario
|
||||
// (el file= es "<username>/<archivo>"; basename lo perdía → not found).
|
||||
if (fileParam.includes("..") || fileParam.startsWith("/") || fileParam.includes("\\")) return null;
|
||||
|
||||
return path.join(CHAT_UPLOADS_DIR, safeName);
|
||||
const fullPath = path.join(CHAT_UPLOADS_DIR, fileParam);
|
||||
// Asegurar que queda dentro de CHAT_UPLOADS_DIR.
|
||||
const base = path.resolve(CHAT_UPLOADS_DIR);
|
||||
if (!path.resolve(fullPath).startsWith(base + path.sep)) return null;
|
||||
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user