Imágenes:
- analyze_image y upload resuelven los bytes por el endpoint Python
/api/image-bytes (pythonGetBinary). analyze_image enruta los dominios
forge (env ACAI_FORGE_DOMAIN) al endpoint en vez de fetch directo (que
daba ECONNREFUSED 127.0.0.1 dentro del container).
Aislamiento de entorno (vscode = solo test):
- resolveCurrentModeOverride(): sesión MCP HTTP (mcpSessionId presente) →
"local"; stdio (chat/cron) → ACAI_MODE_OVERRIDE de entorno. Lo usan los
builders de headers (pythonServerClient, files/helpers) → toda tool del
MCP HTTP manda X-Acai-Mode: local.
- httpServer.resolveProjectCredentials fuerza forceMode:"local" al resolver
project-info → la sesión obtiene web_url/api_web_url forge-local y opera
siempre contra test, nunca producción.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 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>