feat(kiro): add multi-endpoint fallback & thinking mode support

This commit is contained in:
Ravens2121
2025-12-12 13:43:36 +08:00
parent 204bba9dea
commit 84920cb670
7 changed files with 787 additions and 90 deletions
@@ -10,9 +10,18 @@ import (
"github.com/tidwall/sjson"
)
// reasoningEffortToBudget maps OpenAI reasoning_effort values to Claude thinking budget_tokens.
// OpenAI uses "low", "medium", "high" while Claude uses numeric budget_tokens.
var reasoningEffortToBudget = map[string]int{
"low": 4000,
"medium": 16000,
"high": 32000,
}
// ConvertOpenAIRequestToKiro transforms an OpenAI Chat Completions API request into Kiro (Claude) format.
// Kiro uses Claude-compatible format internally, so we primarily pass through to Claude format.
// Supports tool calling: OpenAI tools -> Claude tools, tool_calls -> tool_use, tool messages -> tool_result.
// Supports reasoning/thinking: OpenAI reasoning_effort -> Claude thinking parameter.
func ConvertOpenAIRequestToKiro(modelName string, inputRawJSON []byte, stream bool) []byte {
rawJSON := bytes.Clone(inputRawJSON)
root := gjson.ParseBytes(rawJSON)
@@ -38,6 +47,26 @@ func ConvertOpenAIRequestToKiro(modelName string, inputRawJSON []byte, stream bo
out, _ = sjson.Set(out, "top_p", v.Float())
}
// Handle OpenAI reasoning_effort parameter -> Claude thinking parameter
// OpenAI format: {"reasoning_effort": "low"|"medium"|"high"}
// Claude format: {"thinking": {"type": "enabled", "budget_tokens": N}}
if v := root.Get("reasoning_effort"); v.Exists() {
effort := v.String()
if budget, ok := reasoningEffortToBudget[effort]; ok {
thinking := map[string]interface{}{
"type": "enabled",
"budget_tokens": budget,
}
out, _ = sjson.Set(out, "thinking", thinking)
}
}
// Also support direct thinking parameter passthrough (for Claude API compatibility)
// Claude format: {"thinking": {"type": "enabled", "budget_tokens": N}}
if v := root.Get("thinking"); v.Exists() && v.IsObject() {
out, _ = sjson.Set(out, "thinking", v.Value())
}
// Convert OpenAI tools to Claude tools format
if tools := root.Get("tools"); tools.Exists() && tools.IsArray() {
claudeTools := make([]interface{}, 0)
@@ -134,6 +134,28 @@ func convertClaudeEventToOpenAI(jsonStr string, model string) []string {
result, _ := json.Marshal(response)
results = append(results, string(result))
}
} else if deltaType == "thinking_delta" {
// Thinking/reasoning content delta - convert to OpenAI reasoning_content format
thinkingDelta := root.Get("delta.thinking").String()
if thinkingDelta != "" {
response := map[string]interface{}{
"id": "chatcmpl-" + uuid.New().String()[:24],
"object": "chat.completion.chunk",
"created": time.Now().Unix(),
"model": model,
"choices": []map[string]interface{}{
{
"index": 0,
"delta": map[string]interface{}{
"reasoning_content": thinkingDelta,
},
"finish_reason": nil,
},
},
}
result, _ := json.Marshal(response)
results = append(results, string(result))
}
} else if deltaType == "input_json_delta" {
// Tool input delta (streaming arguments)
partialJSON := root.Get("delta.partial_json").String()
@@ -298,6 +320,7 @@ func ConvertKiroResponseToOpenAINonStream(ctx context.Context, model string, ori
root := gjson.ParseBytes(rawResponse)
var content string
var reasoningContent string
var toolCalls []map[string]interface{}
contentArray := root.Get("content")
@@ -306,6 +329,9 @@ func ConvertKiroResponseToOpenAINonStream(ctx context.Context, model string, ori
itemType := item.Get("type").String()
if itemType == "text" {
content += item.Get("text").String()
} else if itemType == "thinking" {
// Extract thinking/reasoning content
reasoningContent += item.Get("thinking").String()
} else if itemType == "tool_use" {
// Convert Claude tool_use to OpenAI tool_calls format
inputJSON := item.Get("input").String()
@@ -339,6 +365,11 @@ func ConvertKiroResponseToOpenAINonStream(ctx context.Context, model string, ori
"content": content,
}
// Add reasoning_content if present (OpenAI reasoning format)
if reasoningContent != "" {
message["reasoning_content"] = reasoningContent
}
// Add tool_calls if present
if len(toolCalls) > 0 {
message["tool_calls"] = toolCalls