mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-03 04:50:52 +08:00
fix(claude): prevent final events when no content streamed
This commit is contained in:
@@ -35,6 +35,7 @@ type Params struct {
|
|||||||
TotalTokenCount int64 // Cached total token count from usage metadata
|
TotalTokenCount int64 // Cached total token count from usage metadata
|
||||||
HasSentFinalEvents bool // Indicates if final content/message events have been sent
|
HasSentFinalEvents bool // Indicates if final content/message events have been sent
|
||||||
HasToolUse bool // Indicates if tool use was observed in the stream
|
HasToolUse bool // Indicates if tool use was observed in the stream
|
||||||
|
HasContent bool // Tracks whether any content (text, thinking, or tool use) has been output
|
||||||
}
|
}
|
||||||
|
|
||||||
// toolUseIDCounter provides a process-wide unique counter for tool use identifiers.
|
// toolUseIDCounter provides a process-wide unique counter for tool use identifiers.
|
||||||
@@ -69,11 +70,14 @@ func ConvertAntigravityResponseToClaude(_ context.Context, _ string, originalReq
|
|||||||
|
|
||||||
if bytes.Equal(rawJSON, []byte("[DONE]")) {
|
if bytes.Equal(rawJSON, []byte("[DONE]")) {
|
||||||
output := ""
|
output := ""
|
||||||
appendFinalEvents(params, &output, true)
|
// Only send final events if we have actually output content
|
||||||
|
if params.HasContent {
|
||||||
return []string{
|
appendFinalEvents(params, &output, true)
|
||||||
output + "event: message_stop\ndata: {\"type\":\"message_stop\"}\n\n\n",
|
return []string{
|
||||||
|
output + "event: message_stop\ndata: {\"type\":\"message_stop\"}\n\n\n",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
output := ""
|
output := ""
|
||||||
@@ -119,10 +123,12 @@ func ConvertAntigravityResponseToClaude(_ context.Context, _ string, originalReq
|
|||||||
output = output + "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":"signature_delta","signature":""}}`, params.ResponseIndex), "delta.signature", thoughtSignature.String())
|
data, _ := sjson.Set(fmt.Sprintf(`{"type":"content_block_delta","index":%d,"delta":{"type":"signature_delta","signature":""}}`, params.ResponseIndex), "delta.signature", thoughtSignature.String())
|
||||||
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
||||||
|
params.HasContent = true
|
||||||
} else if params.ResponseType == 2 { // Continue existing thinking block if already in thinking state
|
} else if params.ResponseType == 2 { // Continue existing thinking block if already in thinking state
|
||||||
output = output + "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":""}}`, params.ResponseIndex), "delta.thinking", partTextResult.String())
|
data, _ := sjson.Set(fmt.Sprintf(`{"type":"content_block_delta","index":%d,"delta":{"type":"thinking_delta","thinking":""}}`, params.ResponseIndex), "delta.thinking", partTextResult.String())
|
||||||
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
||||||
|
params.HasContent = true
|
||||||
} else {
|
} else {
|
||||||
// Transition from another state to thinking
|
// Transition from another state to thinking
|
||||||
// First, close any existing content block
|
// First, close any existing content block
|
||||||
@@ -146,6 +152,7 @@ func ConvertAntigravityResponseToClaude(_ context.Context, _ string, originalReq
|
|||||||
data, _ := sjson.Set(fmt.Sprintf(`{"type":"content_block_delta","index":%d,"delta":{"type":"thinking_delta","thinking":""}}`, params.ResponseIndex), "delta.thinking", partTextResult.String())
|
data, _ := sjson.Set(fmt.Sprintf(`{"type":"content_block_delta","index":%d,"delta":{"type":"thinking_delta","thinking":""}}`, params.ResponseIndex), "delta.thinking", partTextResult.String())
|
||||||
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
||||||
params.ResponseType = 2 // Set state to thinking
|
params.ResponseType = 2 // Set state to thinking
|
||||||
|
params.HasContent = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
finishReasonResult := gjson.GetBytes(rawJSON, "response.candidates.0.finishReason")
|
finishReasonResult := gjson.GetBytes(rawJSON, "response.candidates.0.finishReason")
|
||||||
@@ -156,6 +163,7 @@ func ConvertAntigravityResponseToClaude(_ context.Context, _ string, originalReq
|
|||||||
output = output + "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":""}}`, params.ResponseIndex), "delta.text", partTextResult.String())
|
data, _ := sjson.Set(fmt.Sprintf(`{"type":"content_block_delta","index":%d,"delta":{"type":"text_delta","text":""}}`, params.ResponseIndex), "delta.text", partTextResult.String())
|
||||||
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
||||||
|
params.HasContent = true
|
||||||
} else {
|
} else {
|
||||||
// Transition from another state to text content
|
// Transition from another state to text content
|
||||||
// First, close any existing content block
|
// First, close any existing content block
|
||||||
@@ -179,6 +187,7 @@ func ConvertAntigravityResponseToClaude(_ context.Context, _ string, originalReq
|
|||||||
data, _ := sjson.Set(fmt.Sprintf(`{"type":"content_block_delta","index":%d,"delta":{"type":"text_delta","text":""}}`, params.ResponseIndex), "delta.text", partTextResult.String())
|
data, _ := sjson.Set(fmt.Sprintf(`{"type":"content_block_delta","index":%d,"delta":{"type":"text_delta","text":""}}`, params.ResponseIndex), "delta.text", partTextResult.String())
|
||||||
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
||||||
params.ResponseType = 1 // Set state to content
|
params.ResponseType = 1 // Set state to content
|
||||||
|
params.HasContent = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -230,6 +239,7 @@ func ConvertAntigravityResponseToClaude(_ context.Context, _ string, originalReq
|
|||||||
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
||||||
}
|
}
|
||||||
params.ResponseType = 3
|
params.ResponseType = 3
|
||||||
|
params.HasContent = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -269,6 +279,11 @@ func appendFinalEvents(params *Params, output *string, force bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only send final events if we have actually output content
|
||||||
|
if !params.HasContent {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if params.ResponseType != 0 {
|
if params.ResponseType != 0 {
|
||||||
*output = *output + "event: content_block_stop\n"
|
*output = *output + "event: content_block_stop\n"
|
||||||
*output = *output + fmt.Sprintf(`data: {"type":"content_block_stop","index":%d}`, params.ResponseIndex)
|
*output = *output + fmt.Sprintf(`data: {"type":"content_block_stop","index":%d}`, params.ResponseIndex)
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ type Params struct {
|
|||||||
HasFirstResponse bool // Indicates if the initial message_start event has been sent
|
HasFirstResponse bool // Indicates if the initial message_start event has been sent
|
||||||
ResponseType int // Current response type: 0=none, 1=content, 2=thinking, 3=function
|
ResponseType int // Current response type: 0=none, 1=content, 2=thinking, 3=function
|
||||||
ResponseIndex int // Index counter for content blocks in the streaming response
|
ResponseIndex int // Index counter for content blocks in the streaming response
|
||||||
|
HasContent bool // Tracks whether any content (text, thinking, or tool use) has been output
|
||||||
}
|
}
|
||||||
|
|
||||||
// toolUseIDCounter provides a process-wide unique counter for tool use identifiers.
|
// toolUseIDCounter provides a process-wide unique counter for tool use identifiers.
|
||||||
@@ -57,9 +58,13 @@ func ConvertGeminiCLIResponseToClaude(_ context.Context, _ string, originalReque
|
|||||||
}
|
}
|
||||||
|
|
||||||
if bytes.Equal(rawJSON, []byte("[DONE]")) {
|
if bytes.Equal(rawJSON, []byte("[DONE]")) {
|
||||||
return []string{
|
// Only send message_stop if we have actually output content
|
||||||
"event: message_stop\ndata: {\"type\":\"message_stop\"}\n\n\n",
|
if (*param).(*Params).HasContent {
|
||||||
|
return []string{
|
||||||
|
"event: message_stop\ndata: {\"type\":\"message_stop\"}\n\n\n",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track whether tools are being used in this response chunk
|
// Track whether tools are being used in this response chunk
|
||||||
@@ -108,6 +113,7 @@ func ConvertGeminiCLIResponseToClaude(_ context.Context, _ string, originalReque
|
|||||||
output = output + "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())
|
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)
|
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
||||||
|
(*param).(*Params).HasContent = true
|
||||||
} else {
|
} else {
|
||||||
// Transition from another state to thinking
|
// Transition from another state to thinking
|
||||||
// First, close any existing content block
|
// First, close any existing content block
|
||||||
@@ -131,6 +137,7 @@ func ConvertGeminiCLIResponseToClaude(_ context.Context, _ string, originalReque
|
|||||||
data, _ := sjson.Set(fmt.Sprintf(`{"type":"content_block_delta","index":%d,"delta":{"type":"thinking_delta","thinking":""}}`, (*param).(*Params).ResponseIndex), "delta.thinking", partTextResult.String())
|
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)
|
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
||||||
(*param).(*Params).ResponseType = 2 // Set state to thinking
|
(*param).(*Params).ResponseType = 2 // Set state to thinking
|
||||||
|
(*param).(*Params).HasContent = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Process regular text content (user-visible output)
|
// Process regular text content (user-visible output)
|
||||||
@@ -139,6 +146,7 @@ func ConvertGeminiCLIResponseToClaude(_ context.Context, _ string, originalReque
|
|||||||
output = output + "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())
|
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)
|
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
||||||
|
(*param).(*Params).HasContent = true
|
||||||
} else {
|
} else {
|
||||||
// Transition from another state to text content
|
// Transition from another state to text content
|
||||||
// First, close any existing content block
|
// First, close any existing content block
|
||||||
@@ -162,6 +170,7 @@ func ConvertGeminiCLIResponseToClaude(_ context.Context, _ string, originalReque
|
|||||||
data, _ := sjson.Set(fmt.Sprintf(`{"type":"content_block_delta","index":%d,"delta":{"type":"text_delta","text":""}}`, (*param).(*Params).ResponseIndex), "delta.text", partTextResult.String())
|
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)
|
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
||||||
(*param).(*Params).ResponseType = 1 // Set state to content
|
(*param).(*Params).ResponseType = 1 // Set state to content
|
||||||
|
(*param).(*Params).HasContent = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if functionCallResult.Exists() {
|
} else if functionCallResult.Exists() {
|
||||||
@@ -211,6 +220,7 @@ func ConvertGeminiCLIResponseToClaude(_ context.Context, _ string, originalReque
|
|||||||
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
||||||
}
|
}
|
||||||
(*param).(*Params).ResponseType = 3
|
(*param).(*Params).ResponseType = 3
|
||||||
|
(*param).(*Params).HasContent = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -219,28 +229,31 @@ func ConvertGeminiCLIResponseToClaude(_ context.Context, _ string, originalReque
|
|||||||
// Process usage metadata and finish reason when present in the response
|
// Process usage metadata and finish reason when present in the response
|
||||||
if usageResult.Exists() && bytes.Contains(rawJSON, []byte(`"finishReason"`)) {
|
if usageResult.Exists() && bytes.Contains(rawJSON, []byte(`"finishReason"`)) {
|
||||||
if candidatesTokenCountResult := usageResult.Get("candidatesTokenCount"); candidatesTokenCountResult.Exists() {
|
if candidatesTokenCountResult := usageResult.Get("candidatesTokenCount"); candidatesTokenCountResult.Exists() {
|
||||||
// Close the final content block
|
// Only send final events if we have actually output content
|
||||||
output = output + "event: content_block_stop\n"
|
if (*param).(*Params).HasContent {
|
||||||
output = output + fmt.Sprintf(`data: {"type":"content_block_stop","index":%d}`, (*param).(*Params).ResponseIndex)
|
// Close the final content block
|
||||||
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"
|
||||||
|
|
||||||
// Send the final message delta with usage information and stop reason
|
// Send the final message delta with usage information and stop reason
|
||||||
output = output + "event: message_delta\n"
|
output = output + "event: message_delta\n"
|
||||||
output = output + `data: `
|
output = output + `data: `
|
||||||
|
|
||||||
// Create the message delta template with appropriate stop reason
|
// Create the message delta template with appropriate stop reason
|
||||||
template := `{"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":0,"output_tokens":0}}`
|
template := `{"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":0,"output_tokens":0}}`
|
||||||
// Set tool_use stop reason if tools were used in this response
|
// Set tool_use stop reason if tools were used in this response
|
||||||
if usedTool {
|
if usedTool {
|
||||||
template = `{"type":"message_delta","delta":{"stop_reason":"tool_use","stop_sequence":null},"usage":{"input_tokens":0,"output_tokens":0}}`
|
template = `{"type":"message_delta","delta":{"stop_reason":"tool_use","stop_sequence":null},"usage":{"input_tokens":0,"output_tokens":0}}`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Include thinking tokens in output token count if present
|
||||||
|
thoughtsTokenCount := usageResult.Get("thoughtsTokenCount").Int()
|
||||||
|
template, _ = sjson.Set(template, "usage.output_tokens", candidatesTokenCountResult.Int()+thoughtsTokenCount)
|
||||||
|
template, _ = sjson.Set(template, "usage.input_tokens", usageResult.Get("promptTokenCount").Int())
|
||||||
|
|
||||||
|
output = output + template + "\n\n\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Include thinking tokens in output token count if present
|
|
||||||
thoughtsTokenCount := usageResult.Get("thoughtsTokenCount").Int()
|
|
||||||
template, _ = sjson.Set(template, "usage.output_tokens", candidatesTokenCountResult.Int()+thoughtsTokenCount)
|
|
||||||
template, _ = sjson.Set(template, "usage.input_tokens", usageResult.Get("promptTokenCount").Int())
|
|
||||||
|
|
||||||
output = output + template + "\n\n\n"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ type Params struct {
|
|||||||
HasFirstResponse bool
|
HasFirstResponse bool
|
||||||
ResponseType int
|
ResponseType int
|
||||||
ResponseIndex int
|
ResponseIndex int
|
||||||
|
HasContent bool // Tracks whether any content (text, thinking, or tool use) has been output
|
||||||
}
|
}
|
||||||
|
|
||||||
// toolUseIDCounter provides a process-wide unique counter for tool use identifiers.
|
// toolUseIDCounter provides a process-wide unique counter for tool use identifiers.
|
||||||
@@ -57,9 +58,13 @@ func ConvertGeminiResponseToClaude(_ context.Context, _ string, originalRequestR
|
|||||||
}
|
}
|
||||||
|
|
||||||
if bytes.Equal(rawJSON, []byte("[DONE]")) {
|
if bytes.Equal(rawJSON, []byte("[DONE]")) {
|
||||||
return []string{
|
// Only send message_stop if we have actually output content
|
||||||
"event: message_stop\ndata: {\"type\":\"message_stop\"}\n\n\n",
|
if (*param).(*Params).HasContent {
|
||||||
|
return []string{
|
||||||
|
"event: message_stop\ndata: {\"type\":\"message_stop\"}\n\n\n",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track whether tools are being used in this response chunk
|
// Track whether tools are being used in this response chunk
|
||||||
@@ -108,6 +113,7 @@ func ConvertGeminiResponseToClaude(_ context.Context, _ string, originalRequestR
|
|||||||
output = output + "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())
|
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)
|
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
||||||
|
(*param).(*Params).HasContent = true
|
||||||
} else {
|
} else {
|
||||||
// Transition from another state to thinking
|
// Transition from another state to thinking
|
||||||
// First, close any existing content block
|
// First, close any existing content block
|
||||||
@@ -131,6 +137,7 @@ func ConvertGeminiResponseToClaude(_ context.Context, _ string, originalRequestR
|
|||||||
data, _ := sjson.Set(fmt.Sprintf(`{"type":"content_block_delta","index":%d,"delta":{"type":"thinking_delta","thinking":""}}`, (*param).(*Params).ResponseIndex), "delta.thinking", partTextResult.String())
|
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)
|
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
||||||
(*param).(*Params).ResponseType = 2 // Set state to thinking
|
(*param).(*Params).ResponseType = 2 // Set state to thinking
|
||||||
|
(*param).(*Params).HasContent = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Process regular text content (user-visible output)
|
// Process regular text content (user-visible output)
|
||||||
@@ -139,6 +146,7 @@ func ConvertGeminiResponseToClaude(_ context.Context, _ string, originalRequestR
|
|||||||
output = output + "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())
|
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)
|
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
||||||
|
(*param).(*Params).HasContent = true
|
||||||
} else {
|
} else {
|
||||||
// Transition from another state to text content
|
// Transition from another state to text content
|
||||||
// First, close any existing content block
|
// First, close any existing content block
|
||||||
@@ -162,6 +170,7 @@ func ConvertGeminiResponseToClaude(_ context.Context, _ string, originalRequestR
|
|||||||
data, _ := sjson.Set(fmt.Sprintf(`{"type":"content_block_delta","index":%d,"delta":{"type":"text_delta","text":""}}`, (*param).(*Params).ResponseIndex), "delta.text", partTextResult.String())
|
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)
|
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
||||||
(*param).(*Params).ResponseType = 1 // Set state to content
|
(*param).(*Params).ResponseType = 1 // Set state to content
|
||||||
|
(*param).(*Params).HasContent = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if functionCallResult.Exists() {
|
} else if functionCallResult.Exists() {
|
||||||
@@ -211,6 +220,7 @@ func ConvertGeminiResponseToClaude(_ context.Context, _ string, originalRequestR
|
|||||||
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
output = output + fmt.Sprintf("data: %s\n\n\n", data)
|
||||||
}
|
}
|
||||||
(*param).(*Params).ResponseType = 3
|
(*param).(*Params).ResponseType = 3
|
||||||
|
(*param).(*Params).HasContent = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -218,23 +228,26 @@ func ConvertGeminiResponseToClaude(_ context.Context, _ string, originalRequestR
|
|||||||
usageResult := gjson.GetBytes(rawJSON, "usageMetadata")
|
usageResult := gjson.GetBytes(rawJSON, "usageMetadata")
|
||||||
if usageResult.Exists() && bytes.Contains(rawJSON, []byte(`"finishReason"`)) {
|
if usageResult.Exists() && bytes.Contains(rawJSON, []byte(`"finishReason"`)) {
|
||||||
if candidatesTokenCountResult := usageResult.Get("candidatesTokenCount"); candidatesTokenCountResult.Exists() {
|
if candidatesTokenCountResult := usageResult.Get("candidatesTokenCount"); candidatesTokenCountResult.Exists() {
|
||||||
output = output + "event: content_block_stop\n"
|
// Only send final events if we have actually output content
|
||||||
output = output + fmt.Sprintf(`data: {"type":"content_block_stop","index":%d}`, (*param).(*Params).ResponseIndex)
|
if (*param).(*Params).HasContent {
|
||||||
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"
|
||||||
|
|
||||||
output = output + "event: message_delta\n"
|
output = output + "event: message_delta\n"
|
||||||
output = output + `data: `
|
output = output + `data: `
|
||||||
|
|
||||||
template := `{"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":0,"output_tokens":0}}`
|
template := `{"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":0,"output_tokens":0}}`
|
||||||
if usedTool {
|
if usedTool {
|
||||||
template = `{"type":"message_delta","delta":{"stop_reason":"tool_use","stop_sequence":null},"usage":{"input_tokens":0,"output_tokens":0}}`
|
template = `{"type":"message_delta","delta":{"stop_reason":"tool_use","stop_sequence":null},"usage":{"input_tokens":0,"output_tokens":0}}`
|
||||||
|
}
|
||||||
|
|
||||||
|
thoughtsTokenCount := usageResult.Get("thoughtsTokenCount").Int()
|
||||||
|
template, _ = sjson.Set(template, "usage.output_tokens", candidatesTokenCountResult.Int()+thoughtsTokenCount)
|
||||||
|
template, _ = sjson.Set(template, "usage.input_tokens", usageResult.Get("promptTokenCount").Int())
|
||||||
|
|
||||||
|
output = output + template + "\n\n\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
thoughtsTokenCount := usageResult.Get("thoughtsTokenCount").Int()
|
|
||||||
template, _ = sjson.Set(template, "usage.output_tokens", candidatesTokenCountResult.Int()+thoughtsTokenCount)
|
|
||||||
template, _ = sjson.Set(template, "usage.input_tokens", usageResult.Get("promptTokenCount").Int())
|
|
||||||
|
|
||||||
output = output + template + "\n\n\n"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user