From ef0edbfe697fed04a271a6cdee719670c22fa31e Mon Sep 17 00:00:00 2001 From: Luis Pater Date: Thu, 11 Dec 2025 22:34:06 +0800 Subject: [PATCH] refactor(claude): replace `strings.Builder` with simpler `output` string concatenation --- .../claude/gemini-cli_claude_response.go | 81 +++++++++++-------- 1 file changed, 49 insertions(+), 32 deletions(-) diff --git a/internal/translator/gemini-cli/claude/gemini-cli_claude_response.go b/internal/translator/gemini-cli/claude/gemini-cli_claude_response.go index 92061086..ca905f9e 100644 --- a/internal/translator/gemini-cli/claude/gemini-cli_claude_response.go +++ b/internal/translator/gemini-cli/claude/gemini-cli_claude_response.go @@ -69,12 +69,12 @@ func ConvertGeminiCLIResponseToClaude(_ context.Context, _ string, originalReque // Track whether tools are being used in this response chunk usedTool := false - var sb strings.Builder + output := "" // Initialize the streaming session with a message_start event // This is only sent for the very first response chunk to establish the streaming session if !(*param).(*Params).HasFirstResponse { - sb.WriteString("event: message_start\n") + output = "event: message_start\n" // Create the initial message structure with default values according to Claude Code API specification // This follows the Claude Code API specification for streaming message initialization @@ -87,7 +87,7 @@ func ConvertGeminiCLIResponseToClaude(_ context.Context, _ string, originalReque if responseIDResult := gjson.GetBytes(rawJSON, "response.responseId"); responseIDResult.Exists() { messageStartTemplate, _ = sjson.Set(messageStartTemplate, "message.id", responseIDResult.String()) } - sb.WriteString(fmt.Sprintf("data: %s\n\n\n", messageStartTemplate)) + output = output + fmt.Sprintf("data: %s\n\n\n", messageStartTemplate) (*param).(*Params).HasFirstResponse = true } @@ -110,7 +110,7 @@ func ConvertGeminiCLIResponseToClaude(_ context.Context, _ string, originalReque if partResult.Get("thought").Bool() { // Continue existing thinking block if already in thinking state if (*param).(*Params).ResponseType == 2 { - sb.WriteString("event: content_block_delta\n") + output = output + "event: content_block_delta\n" data, _ := sjson.Set(fmt.Sprintf(`{"type":"content_block_delta","index":%d,"delta":{"type":"thinking_delta","thinking":""}}`, (*param).(*Params).ResponseIndex), "delta.thinking", partTextResult.String()) output = output + fmt.Sprintf("data: %s\n\n\n", data) (*param).(*Params).HasContent = true @@ -118,19 +118,24 @@ func ConvertGeminiCLIResponseToClaude(_ context.Context, _ string, originalReque // Transition from another state to thinking // First, close any existing content block if (*param).(*Params).ResponseType != 0 { - sb.WriteString("event: content_block_stop\n") - sb.WriteString(fmt.Sprintf(`data: {"type":"content_block_stop","index":%d}`, (*param).(*Params).ResponseIndex)) - sb.WriteString("\n\n\n") + if (*param).(*Params).ResponseType == 2 { + // output = output + "event: content_block_delta\n" + // output = output + fmt.Sprintf(`data: {"type":"content_block_delta","index":%d,"delta":{"type":"signature_delta","signature":null}}`, (*param).(*Params).ResponseIndex) + // output = output + "\n\n\n" + } + output = output + "event: content_block_stop\n" + output = output + fmt.Sprintf(`data: {"type":"content_block_stop","index":%d}`, (*param).(*Params).ResponseIndex) + output = output + "\n\n\n" (*param).(*Params).ResponseIndex++ } // Start a new thinking content block - sb.WriteString("event: content_block_start\n") - sb.WriteString(fmt.Sprintf(`data: {"type":"content_block_start","index":%d,"content_block":{"type":"thinking","thinking":""}}`, (*param).(*Params).ResponseIndex)) - sb.WriteString("\n\n\n") - sb.WriteString("event: content_block_delta\n") + output = output + "event: content_block_start\n" + output = output + fmt.Sprintf(`data: {"type":"content_block_start","index":%d,"content_block":{"type":"thinking","thinking":""}}`, (*param).(*Params).ResponseIndex) + output = output + "\n\n\n" + output = output + "event: content_block_delta\n" data, _ := sjson.Set(fmt.Sprintf(`{"type":"content_block_delta","index":%d,"delta":{"type":"thinking_delta","thinking":""}}`, (*param).(*Params).ResponseIndex), "delta.thinking", partTextResult.String()) - sb.WriteString(fmt.Sprintf("data: %s\n\n\n", data)) + output = output + fmt.Sprintf("data: %s\n\n\n", data) (*param).(*Params).ResponseType = 2 // Set state to thinking (*param).(*Params).HasContent = true } @@ -138,7 +143,7 @@ func ConvertGeminiCLIResponseToClaude(_ context.Context, _ string, originalReque // Process regular text content (user-visible output) // Continue existing text block if already in content state if (*param).(*Params).ResponseType == 1 { - sb.WriteString("event: content_block_delta\n") + output = output + "event: content_block_delta\n" data, _ := sjson.Set(fmt.Sprintf(`{"type":"content_block_delta","index":%d,"delta":{"type":"text_delta","text":""}}`, (*param).(*Params).ResponseIndex), "delta.text", partTextResult.String()) output = output + fmt.Sprintf("data: %s\n\n\n", data) (*param).(*Params).HasContent = true @@ -146,19 +151,24 @@ func ConvertGeminiCLIResponseToClaude(_ context.Context, _ string, originalReque // Transition from another state to text content // First, close any existing content block if (*param).(*Params).ResponseType != 0 { - sb.WriteString("event: content_block_stop\n") - sb.WriteString(fmt.Sprintf(`data: {"type":"content_block_stop","index":%d}`, (*param).(*Params).ResponseIndex)) - sb.WriteString("\n\n\n") + if (*param).(*Params).ResponseType == 2 { + // output = output + "event: content_block_delta\n" + // output = output + fmt.Sprintf(`data: {"type":"content_block_delta","index":%d,"delta":{"type":"signature_delta","signature":null}}`, (*param).(*Params).ResponseIndex) + // output = output + "\n\n\n" + } + output = output + "event: content_block_stop\n" + output = output + fmt.Sprintf(`data: {"type":"content_block_stop","index":%d}`, (*param).(*Params).ResponseIndex) + output = output + "\n\n\n" (*param).(*Params).ResponseIndex++ } // Start a new text content block - sb.WriteString("event: content_block_start\n") - sb.WriteString(fmt.Sprintf(`data: {"type":"content_block_start","index":%d,"content_block":{"type":"text","text":""}}`, (*param).(*Params).ResponseIndex)) - sb.WriteString("\n\n\n") - sb.WriteString("event: content_block_delta\n") + output = output + "event: content_block_start\n" + output = output + fmt.Sprintf(`data: {"type":"content_block_start","index":%d,"content_block":{"type":"text","text":""}}`, (*param).(*Params).ResponseIndex) + output = output + "\n\n\n" + output = output + "event: content_block_delta\n" data, _ := sjson.Set(fmt.Sprintf(`{"type":"content_block_delta","index":%d,"delta":{"type":"text_delta","text":""}}`, (*param).(*Params).ResponseIndex), "delta.text", partTextResult.String()) - sb.WriteString(fmt.Sprintf("data: %s\n\n\n", data)) + output = output + fmt.Sprintf("data: %s\n\n\n", data) (*param).(*Params).ResponseType = 1 // Set state to content (*param).(*Params).HasContent = true } @@ -172,35 +182,42 @@ func ConvertGeminiCLIResponseToClaude(_ context.Context, _ string, originalReque // Handle state transitions when switching to function calls // Close any existing function call block first if (*param).(*Params).ResponseType == 3 { - sb.WriteString("event: content_block_stop\n") - sb.WriteString(fmt.Sprintf(`data: {"type":"content_block_stop","index":%d}`, (*param).(*Params).ResponseIndex)) - sb.WriteString("\n\n\n") + output = output + "event: content_block_stop\n" + output = output + fmt.Sprintf(`data: {"type":"content_block_stop","index":%d}`, (*param).(*Params).ResponseIndex) + output = output + "\n\n\n" (*param).(*Params).ResponseIndex++ (*param).(*Params).ResponseType = 0 } + // Special handling for thinking state transition + if (*param).(*Params).ResponseType == 2 { + // output = output + "event: content_block_delta\n" + // output = output + fmt.Sprintf(`data: {"type":"content_block_delta","index":%d,"delta":{"type":"signature_delta","signature":null}}`, (*param).(*Params).ResponseIndex) + // output = output + "\n\n\n" + } + // Close any other existing content block if (*param).(*Params).ResponseType != 0 { - sb.WriteString("event: content_block_stop\n") - sb.WriteString(fmt.Sprintf(`data: {"type":"content_block_stop","index":%d}`, (*param).(*Params).ResponseIndex)) - sb.WriteString("\n\n\n") + output = output + "event: content_block_stop\n" + output = output + fmt.Sprintf(`data: {"type":"content_block_stop","index":%d}`, (*param).(*Params).ResponseIndex) + output = output + "\n\n\n" (*param).(*Params).ResponseIndex++ } // Start a new tool use content block // This creates the structure for a function call in Claude Code format - sb.WriteString("event: content_block_start\n") + output = output + "event: content_block_start\n" // Create the tool use block with unique ID and function details data := fmt.Sprintf(`{"type":"content_block_start","index":%d,"content_block":{"type":"tool_use","id":"","name":"","input":{}}}`, (*param).(*Params).ResponseIndex) data, _ = sjson.Set(data, "content_block.id", fmt.Sprintf("%s-%d-%d", fcName, time.Now().UnixNano(), atomic.AddUint64(&toolUseIDCounter, 1))) data, _ = sjson.Set(data, "content_block.name", fcName) - sb.WriteString(fmt.Sprintf("data: %s\n\n\n", data)) + output = output + fmt.Sprintf("data: %s\n\n\n", data) if fcArgsResult := functionCallResult.Get("args"); fcArgsResult.Exists() { - sb.WriteString("event: content_block_delta\n") + output = output + "event: content_block_delta\n" data, _ = sjson.Set(fmt.Sprintf(`{"type":"content_block_delta","index":%d,"delta":{"type":"input_json_delta","partial_json":""}}`, (*param).(*Params).ResponseIndex), "delta.partial_json", fcArgsResult.Raw) - sb.WriteString(fmt.Sprintf("data: %s\n\n\n", data)) + output = output + fmt.Sprintf("data: %s\n\n\n", data) } (*param).(*Params).ResponseType = 3 (*param).(*Params).HasContent = true @@ -240,7 +257,7 @@ func ConvertGeminiCLIResponseToClaude(_ context.Context, _ string, originalReque } } - return []string{sb.String()} + return []string{output} } // ConvertGeminiCLIResponseToClaudeNonStream converts a non-streaming Gemini CLI response to a non-streaming Claude response.