Merge branch 'pr-454'

# Conflicts:
#	cmd/server/main.go
#	internal/translator/claude/openai/chat-completions/claude_openai_response.go
This commit is contained in:
Luis Pater
2026-03-22 22:52:46 +08:00
87 changed files with 3259 additions and 3117 deletions

View File

@@ -10,12 +10,12 @@ import (
// ConvertKiroStreamToClaude converts Kiro streaming response to Claude format.
// Kiro executor already generates complete SSE format with "event:" prefix,
// so this is a simple pass-through.
func ConvertKiroStreamToClaude(ctx context.Context, model string, originalRequest, request, rawResponse []byte, param *any) []string {
return []string{string(rawResponse)}
func ConvertKiroStreamToClaude(ctx context.Context, model string, originalRequest, request, rawResponse []byte, param *any) [][]byte {
return [][]byte{rawResponse}
}
// ConvertKiroNonStreamToClaude converts Kiro non-streaming response to Claude format.
// The response is already in Claude format, so this is a pass-through.
func ConvertKiroNonStreamToClaude(ctx context.Context, model string, originalRequest, request, rawResponse []byte, param *any) string {
return string(rawResponse)
func ConvertKiroNonStreamToClaude(ctx context.Context, model string, originalRequest, request, rawResponse []byte, param *any) []byte {
return rawResponse
}

View File

@@ -32,7 +32,7 @@ import (
// OpenAI SSE format:
// - data: {"id":"...","object":"chat.completion.chunk",...}
// - data: [DONE]
func ConvertKiroStreamToOpenAI(ctx context.Context, model string, originalRequest, request, rawResponse []byte, param *any) []string {
func ConvertKiroStreamToOpenAI(ctx context.Context, model string, originalRequest, request, rawResponse []byte, param *any) [][]byte {
// Initialize state if needed
if *param == nil {
*param = NewOpenAIStreamState(model)
@@ -64,13 +64,13 @@ func ConvertKiroStreamToOpenAI(ctx context.Context, model string, originalReques
}
if eventData == "" {
return []string{}
return [][]byte{}
}
// Parse the event data as JSON
eventJSON := gjson.Parse(eventData)
if !eventJSON.Exists() {
return []string{}
return [][]byte{}
}
// Determine event type from JSON if not already set
@@ -78,13 +78,13 @@ func ConvertKiroStreamToOpenAI(ctx context.Context, model string, originalReques
eventType = eventJSON.Get("type").String()
}
var results []string
var results [][]byte
switch eventType {
case "message_start":
// Send first chunk with role
firstChunk := BuildOpenAISSEFirstChunk(state)
results = append(results, firstChunk)
results = append(results, []byte(firstChunk))
case "content_block_start":
// Check block type
@@ -99,7 +99,7 @@ func ConvertKiroStreamToOpenAI(ctx context.Context, model string, originalReques
toolUseID := eventJSON.Get("content_block.id").String()
toolName := eventJSON.Get("content_block.name").String()
chunk := BuildOpenAISSEToolCallStart(state, toolUseID, toolName)
results = append(results, chunk)
results = append(results, []byte(chunk))
state.ToolCallIndex++
}
@@ -110,14 +110,14 @@ func ConvertKiroStreamToOpenAI(ctx context.Context, model string, originalReques
textDelta := eventJSON.Get("delta.text").String()
if textDelta != "" {
chunk := BuildOpenAISSETextDelta(state, textDelta)
results = append(results, chunk)
results = append(results, []byte(chunk))
}
case "thinking_delta":
// Convert thinking to reasoning_content for o1-style compatibility
thinkingDelta := eventJSON.Get("delta.thinking").String()
if thinkingDelta != "" {
chunk := BuildOpenAISSEReasoningDelta(state, thinkingDelta)
results = append(results, chunk)
results = append(results, []byte(chunk))
}
case "input_json_delta":
// Tool call arguments delta
@@ -126,7 +126,7 @@ func ConvertKiroStreamToOpenAI(ctx context.Context, model string, originalReques
// Get the tool index from content block index
blockIndex := int(eventJSON.Get("index").Int())
chunk := BuildOpenAISSEToolCallArgumentsDelta(state, partialJSON, blockIndex-1) // Adjust for 0-based tool index
results = append(results, chunk)
results = append(results, []byte(chunk))
}
}
@@ -139,7 +139,7 @@ func ConvertKiroStreamToOpenAI(ctx context.Context, model string, originalReques
finishReason := mapKiroStopReasonToOpenAI(stopReason)
if finishReason != "" {
chunk := BuildOpenAISSEFinish(state, finishReason)
results = append(results, chunk)
results = append(results, []byte(chunk))
}
// Extract usage if present
@@ -152,7 +152,7 @@ func ConvertKiroStreamToOpenAI(ctx context.Context, model string, originalReques
TotalTokens: inputTokens + outputTokens,
}
chunk := BuildOpenAISSEUsage(state, usageInfo)
results = append(results, chunk)
results = append(results, []byte(chunk))
}
case "message_stop":
@@ -171,7 +171,7 @@ func ConvertKiroStreamToOpenAI(ctx context.Context, model string, originalReques
TotalTokens: inputTokens + outputTokens,
}
chunk := BuildOpenAISSEUsage(state, usageInfo)
results = append(results, chunk)
results = append(results, []byte(chunk))
}
}
@@ -181,7 +181,7 @@ func ConvertKiroStreamToOpenAI(ctx context.Context, model string, originalReques
// ConvertKiroNonStreamToOpenAI converts Kiro non-streaming response to OpenAI format.
// The Kiro executor returns Claude-compatible JSON responses, so this function translates
// from Claude format to OpenAI format.
func ConvertKiroNonStreamToOpenAI(ctx context.Context, model string, originalRequest, request, rawResponse []byte, param *any) string {
func ConvertKiroNonStreamToOpenAI(ctx context.Context, model string, originalRequest, request, rawResponse []byte, param *any) []byte {
// Parse the Claude-format response
response := gjson.ParseBytes(rawResponse)
@@ -237,7 +237,7 @@ func ConvertKiroNonStreamToOpenAI(ctx context.Context, model string, originalReq
// Build OpenAI response with reasoning_content support
openaiResponse := BuildOpenAIResponseWithReasoning(content, reasoningContent, toolUses, model, usageInfo, stopReason)
return string(openaiResponse)
return openaiResponse
}
// ParseClaudeEvent parses a Claude SSE event and returns the event type and data