feat(codex): handle thinking-signature conversion for reasoning content
- Implemented `appendReasoningContent` to support processing of `thinking` signature and text as reasoning input. - Added test cases to validate reasoning content conversion with and without text.
This commit is contained in:
@@ -120,6 +120,30 @@ func ConvertClaudeRequestToCodex(modelName string, inputRawJSON []byte, _ bool)
|
|||||||
hasContent = true
|
hasContent = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
appendReasoningContent := func(part gjson.Result) {
|
||||||
|
if messageRole != "assistant" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
thinkingText := thinking.GetThinkingText(part)
|
||||||
|
signature := part.Get("signature").String()
|
||||||
|
if strings.TrimSpace(thinkingText) == "" && signature == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
reasoningItem := []byte(`{"type":"reasoning","summary":[]}`)
|
||||||
|
if signature != "" {
|
||||||
|
reasoningItem, _ = sjson.SetBytes(reasoningItem, "encrypted_content", signature)
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(thinkingText) != "" {
|
||||||
|
summary := []byte(`{"type":"summary_text","text":""}`)
|
||||||
|
summary, _ = sjson.SetBytes(summary, "text", thinkingText)
|
||||||
|
reasoningItem, _ = sjson.SetRawBytes(reasoningItem, "summary.-1", summary)
|
||||||
|
}
|
||||||
|
|
||||||
|
template, _ = sjson.SetRawBytes(template, "input.-1", reasoningItem)
|
||||||
|
}
|
||||||
|
|
||||||
messageContentsResult := messageResult.Get("content")
|
messageContentsResult := messageResult.Get("content")
|
||||||
if messageContentsResult.IsArray() {
|
if messageContentsResult.IsArray() {
|
||||||
messageContentResults := messageContentsResult.Array()
|
messageContentResults := messageContentsResult.Array()
|
||||||
@@ -130,6 +154,9 @@ func ConvertClaudeRequestToCodex(modelName string, inputRawJSON []byte, _ bool)
|
|||||||
switch contentType {
|
switch contentType {
|
||||||
case "text":
|
case "text":
|
||||||
appendTextContent(messageContentResult.Get("text").String())
|
appendTextContent(messageContentResult.Get("text").String())
|
||||||
|
case "thinking":
|
||||||
|
flushMessage()
|
||||||
|
appendReasoningContent(messageContentResult)
|
||||||
case "image":
|
case "image":
|
||||||
sourceResult := messageContentResult.Get("source")
|
sourceResult := messageContentResult.Get("source")
|
||||||
if sourceResult.Exists() {
|
if sourceResult.Exists() {
|
||||||
|
|||||||
@@ -133,3 +133,75 @@ func TestConvertClaudeRequestToCodex_ParallelToolCalls(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConvertClaudeRequestToCodex_ThinkingSignatureToEncryptedContent(t *testing.T) {
|
||||||
|
result := ConvertClaudeRequestToCodex("test-model", []byte(`{
|
||||||
|
"model": "claude-3-opus",
|
||||||
|
"messages": [{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": [
|
||||||
|
{"type": "thinking", "thinking": "Internal reasoning.", "signature": "sig_123"},
|
||||||
|
{"type": "text", "text": "Visible answer."}
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
}`), false)
|
||||||
|
resultJSON := gjson.ParseBytes(result)
|
||||||
|
inputs := resultJSON.Get("input").Array()
|
||||||
|
|
||||||
|
if len(inputs) != 2 {
|
||||||
|
t.Fatalf("got %d input items, want 2. Output: %s", len(inputs), string(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
reasoning := inputs[0]
|
||||||
|
if got := reasoning.Get("type").String(); got != "reasoning" {
|
||||||
|
t.Fatalf("input[0].type = %q, want %q. Output: %s", got, "reasoning", string(result))
|
||||||
|
}
|
||||||
|
if got := reasoning.Get("encrypted_content").String(); got != "sig_123" {
|
||||||
|
t.Fatalf("encrypted_content = %q, want %q. Output: %s", got, "sig_123", string(result))
|
||||||
|
}
|
||||||
|
if got := reasoning.Get("summary.0.type").String(); got != "summary_text" {
|
||||||
|
t.Fatalf("summary.0.type = %q, want %q. Output: %s", got, "summary_text", string(result))
|
||||||
|
}
|
||||||
|
if got := reasoning.Get("summary.0.text").String(); got != "Internal reasoning." {
|
||||||
|
t.Fatalf("summary.0.text = %q, want %q. Output: %s", got, "Internal reasoning.", string(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
message := inputs[1]
|
||||||
|
if got := message.Get("type").String(); got != "message" {
|
||||||
|
t.Fatalf("input[1].type = %q, want %q. Output: %s", got, "message", string(result))
|
||||||
|
}
|
||||||
|
if got := message.Get("role").String(); got != "assistant" {
|
||||||
|
t.Fatalf("input[1].role = %q, want %q. Output: %s", got, "assistant", string(result))
|
||||||
|
}
|
||||||
|
if got := message.Get("content.0.type").String(); got != "output_text" {
|
||||||
|
t.Fatalf("content.0.type = %q, want %q. Output: %s", got, "output_text", string(result))
|
||||||
|
}
|
||||||
|
if got := message.Get("content.0.text").String(); got != "Visible answer." {
|
||||||
|
t.Fatalf("content.0.text = %q, want %q. Output: %s", got, "Visible answer.", string(result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertClaudeRequestToCodex_ThinkingSignatureWithoutText(t *testing.T) {
|
||||||
|
result := ConvertClaudeRequestToCodex("test-model", []byte(`{
|
||||||
|
"model": "claude-3-opus",
|
||||||
|
"messages": [{
|
||||||
|
"role": "assistant",
|
||||||
|
"content": [{"type": "thinking", "thinking": "", "signature": "sig_empty_text"}]
|
||||||
|
}]
|
||||||
|
}`), false)
|
||||||
|
resultJSON := gjson.ParseBytes(result)
|
||||||
|
inputs := resultJSON.Get("input").Array()
|
||||||
|
|
||||||
|
if len(inputs) != 1 {
|
||||||
|
t.Fatalf("got %d input items, want 1. Output: %s", len(inputs), string(result))
|
||||||
|
}
|
||||||
|
if got := inputs[0].Get("type").String(); got != "reasoning" {
|
||||||
|
t.Fatalf("input[0].type = %q, want %q. Output: %s", got, "reasoning", string(result))
|
||||||
|
}
|
||||||
|
if got := inputs[0].Get("encrypted_content").String(); got != "sig_empty_text" {
|
||||||
|
t.Fatalf("encrypted_content = %q, want %q. Output: %s", got, "sig_empty_text", string(result))
|
||||||
|
}
|
||||||
|
if got := len(inputs[0].Get("summary").Array()); got != 0 {
|
||||||
|
t.Fatalf("summary length = %d, want 0. Output: %s", got, string(result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user