From 325acdba8cde154551a6c90e506210cd8e5db9c5 Mon Sep 17 00:00:00 2001 From: Badri Narayanan S Date: Sun, 11 Jan 2026 11:52:35 +0530 Subject: [PATCH] fix: preserve tool_use stop reason from being overwritten by finishReason When a tool call is made, stopReason is set to 'tool_use'. However, when finishReason: STOP arrives later, it was overwriting stopReason back to 'end_turn', breaking multi-turn tool conversations in clients like OpenCode. Fix: Initialize stopReason to null and only set it from finishReason if not already set. This ensures tool_use is preserved once detected. Fixes #96 Co-Authored-By: Claude --- src/cloudcode/sse-streamer.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cloudcode/sse-streamer.js b/src/cloudcode/sse-streamer.js index b591279..3fe80a1 100644 --- a/src/cloudcode/sse-streamer.js +++ b/src/cloudcode/sse-streamer.js @@ -27,7 +27,7 @@ export async function* streamSSEResponse(response, originalModel) { let inputTokens = 0; let outputTokens = 0; let cacheReadTokens = 0; - let stopReason = 'end_turn'; + let stopReason = null; const reader = response.body.getReader(); const decoder = new TextDecoder(); @@ -212,8 +212,8 @@ export async function* streamSSEResponse(response, originalModel) { } } - // Check finish reason - if (firstCandidate.finishReason) { + // Check finish reason (only if not already set by tool_use) + if (firstCandidate.finishReason && !stopReason) { if (firstCandidate.finishReason === 'MAX_TOKENS') { stopReason = 'max_tokens'; } else if (firstCandidate.finishReason === 'STOP') { @@ -248,7 +248,7 @@ export async function* streamSSEResponse(response, originalModel) { // Emit message_delta and message_stop yield { type: 'message_delta', - delta: { stop_reason: stopReason, stop_sequence: null }, + delta: { stop_reason: stopReason || 'end_turn', stop_sequence: null }, usage: { output_tokens: outputTokens, cache_read_input_tokens: cacheReadTokens,