Reportar modelo real en no-streaming + prewarm de mcp-server-fetch

- engine.py: process_message ahora incluye model/modelUsage en el dict de
  retorno (no solo en el evento SSE), para que el camino no-streaming
  (cronjobs -> _report_usage) reporte el modelo real a consumo_acaicode en
  vez de "unknown".
- Dockerfile: precalentar `uvx mcp-server-fetch` en build (como appuser) para
  que la cache de uv quede en la imagen y el MCP fetch no se quede sin arrancar
  por timeout en frio tras un rebuild.
- mcp.json: startup_timeout de fetch 15 -> 30s como margen.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jordan
2026-06-22 13:20:51 +01:00
parent 882d578960
commit 037bc81936
3 changed files with 23 additions and 1 deletions

View File

@@ -56,6 +56,13 @@ USER appuser
# Descargar Chromium como appuser (queda en ~/.cache/ms-playwright/)
RUN cd mcp-server && npx playwright install chromium
# Precalentar mcp-server-fetch como appuser: uvx descarga ~43 paquetes la
# primera vez, lo que en frio supera el startup_timeout del MCP. Lo dejamos
# cacheado en ~/.cache/uv dentro de la imagen para que arranque rapido en
# runtime (igual que Chromium). El server lee stdin; con </dev/null sale tras
# instalar. `|| true` para no romper el build si sale != 0.
RUN timeout 180 uvx mcp-server-fetch </dev/null >/dev/null 2>&1 || true
EXPOSE 8000
CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]

View File

@@ -19,7 +19,7 @@
"command": "uvx",
"args": ["mcp-server-fetch"],
"timeout": 30,
"startup_timeout": 15
"startup_timeout": 30
}
}
}

View File

@@ -267,6 +267,21 @@ class OrchestratorEngine:
"status": "completed",
"usage": usage,
"total_cost_usd": round(cost_usd, 6),
# Modelo + tarifas realmente usadas. Se incluyen tambien aqui (ademas
# del evento SSE EXECUTION_COMPLETED) para que el camino NO streaming
# (cronjobs -> _report_usage) reporte el modelo correcto a
# consumo_acaicode en vez de "unknown".
"model": model_used,
"modelUsage": {
model_used: {
"inputTokens": total_input,
"outputTokens": total_output,
"costUSD": round(cost_usd, 6),
"inputCost1M": cost_info["input_cost_1m"],
"outputCost1M": cost_info["output_cost_1m"],
"reasoningEffort": self.agent_profile.reasoning_effort or "",
}
},
}
def _error_result(self, session: SessionState, error: str) -> dict[str, Any]: