- session_lock: token uuid + compare-and-delete (Lua), TTL > timeout de
ejecucion; abort solo limpia el lock tras cancelacion confirmada.
Evita doble ejecucion concurrente sobre la misma sesion.
- monitor HTTP (puerto 4545) deshabilitado salvo MCP_MONITOR_ENABLED=true
y atado a 127.0.0.1; no se acumula historial en memoria si esta off.
- DeepSeek/LiteLLM: turnos que llegan solo con reasoning_content (sin
content ni tool_calls) ya no rompen la sesion (400 'Invalid assistant
message') ni se pintan como 'pensando': se promueven a texto en el
historial y en el snapshot persistido.
- litellm pinneado a ==1.80.0 (builds reproducibles).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Tercer modo de fallo del conector OpenAI (distinto de followup_mode y de
finish_reason=stop): DeepSeek a veces emite las tool calls en su formato interno
DSML (<||DSML||tool_calls>…, con U+FF5C) como TEXTO en el content, en vez de
como tool_calls nativos. El endpoint OpenAI no lo convierte, asi que el adapter
lo trataba como texto y el agente "se paraba" mostrando DSML inerte (0 tools).
Fix en OpenAIAdapter.stream: reutiliza el parser del claude_adapter
(_parse_xml_tool_calls / _TOOL_CALL_OPEN_RE). Acumula el content; si detecta el
inicio de un tool call en texto deja de emitirlo al usuario (DSML no debe verse);
al cerrar el turno, si no hubo tool_calls nativos, parsea el content y emite los
tool calls encontrados como tool_use para que el engine los ejecute.
Validado: el DSML real de la sesion (2x acai_grep) se parsea correctamente.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sintoma (solo con el conector OpenAI): el agente anuncia la accion en texto
("Voy a crear los modulos…") y se PARA sin ejecutarla — 0 tools.
Causa: el stream del OpenAIAdapter solo emitia los tool_calls acumulados cuando
choice.finish_reason == "tool_calls". Pero DeepSeek (endpoint OpenAI) a veces
cierra el stream con finish_reason="stop" AUNQUE haya emitido tool_calls; en ese
caso caiamos en el branch else (end_turn) y los tool_calls acumulados se
descartaban. base.py solo ejecuta al recibir finish_reason="tool_use", asi que
nunca se ejecutaban. Con el adapter Claude (Anthropic) el finish_reason venia
distinto, por eso solo aparecia tras el cambio de conector.
Fix: disparar los tool_use SIEMPRE que haya tool_calls acumulados al cerrar el
stream, sea cual sea el finish_reason.
Validado: "crea un modulo…" ahora ejecuta acai_write + check_module y completa,
en vez de pararse tras anunciar.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Dos bugs encadenados impedían que el agente ejecutara tools (emitía los tool
calls como texto sin ejecutarlos, y degradaba el contexto):
1. Conector: el OpenAIAdapter pasaba los mensajes en formato Anthropic (bloques
tool_use/tool_result) que la API OpenAI de DeepSeek rechaza, y defaulteaba el
modelo a "gpt-4o". Añade `_to_openai_messages()` (assistant.tool_use →
tool_calls; user.tool_result → role:tool con tool_call_id) y `_blocks_text()`,
y usa `settings.default_model_id`. Con esto DeepSeek devuelve tool_calls
nativos vía https://api.deepseek.com (endpoint OpenAI), sin parsear texto y
sin la degradación que sufría el endpoint Anthropic-compat.
2. followup_mode: `_classify_followup_mode` marcaba como "transform" cualquier
PRIMER mensaje que contuviera un marker ("resumen", "estructura", "busca",
"adapta"…), y `_get_allowed_tools` devuelve [] en modo transform → el agente
se quedaba SIN tools. Un follow-up no tiene sentido sin turno anterior, así
que ahora solo se clasifica si hay task_history/recent_messages.
claude_adapter: parser DSML/DeepSeek para tool calls como texto (fallback del
endpoint Anthropic-compat, ya no es la vía principal).
Validado: el prompt de análisis de estilos ("Guarda un resumen…") ahora explora
los módulos y escribe docs/project-styles.md vía save_project_styles.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Nueva variable AGENTIC_OPENAI_BASE_URL para proveedores compatibles
con OpenAI API (MiniMax, DeepInfra, Together, etc.).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Config: COST_PER_1M_INPUT y COST_PER_1M_OUTPUT configurables via .env
- OpenAI adapter: stream_options include_usage para capturar tokens reales
- base.py: acumula input/output tokens de cada iteración del agente
- planner.py: devuelve usage junto con el plan
- engine.py: suma tokens de planner + steps + review, calcula coste USD
- Response incluye usage{input_tokens, output_tokens} y total_cost_usd
Formato compatible con el bridge de Claude Code CLI para integración
con el frontend y reporting a Acai webservice.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>