From d6b04e4122a3ccbeca46bd74b1b92b6521973faa Mon Sep 17 00:00:00 2001 From: Jordan Diaz Date: Fri, 5 Jun 2026 17:55:40 +0000 Subject: [PATCH] fix(adapter): no perder tool_calls cuando DeepSeek cierra con finish_reason=stop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- src/adapters/openai_adapter.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/adapters/openai_adapter.py b/src/adapters/openai_adapter.py index d2e0a50..7229fac 100644 --- a/src/adapters/openai_adapter.py +++ b/src/adapters/openai_adapter.py @@ -109,7 +109,13 @@ class OpenAIAdapter(ModelAdapter): # Finish if choice.finish_reason: - if choice.finish_reason == "tool_calls": + # IMPORTANTE: DeepSeek (endpoint OpenAI) a veces cierra el stream + # con finish_reason="stop" AUNQUE haya emitido tool_calls. Si nos + # fiamos solo de =="tool_calls" perdemos esos tool calls: el agente + # anuncia la accion en texto y "se para" sin ejecutarla. Por eso + # disparamos los tool_use SIEMPRE que haya tool calls acumulados, + # sea cual sea el finish_reason. + if tool_calls_acc: for acc in tool_calls_acc.values(): yield StreamChunk( tool_call_id=acc["id"], @@ -123,7 +129,7 @@ class OpenAIAdapter(ModelAdapter): else: yield StreamChunk( finish_reason="end_turn" - if choice.finish_reason == "stop" + if choice.finish_reason in ("stop", "tool_calls") else choice.finish_reason, usage=final_usage, )