fix: retain codex thinking signature until item done
This commit is contained in:
@@ -179,8 +179,11 @@ func ConvertCodexResponseToClaude(_ context.Context, _ string, originalRequestRa
|
|||||||
|
|
||||||
output = translatorcommon.AppendSSEEventBytes(output, "content_block_stop", template, 2)
|
output = translatorcommon.AppendSSEEventBytes(output, "content_block_stop", template, 2)
|
||||||
} else if itemType == "reasoning" {
|
} else if itemType == "reasoning" {
|
||||||
params.ThinkingSignature = itemResult.Get("encrypted_content").String()
|
if signature := itemResult.Get("encrypted_content").String(); signature != "" {
|
||||||
|
params.ThinkingSignature = signature
|
||||||
|
}
|
||||||
output = append(output, finalizeCodexThinkingBlock(params)...)
|
output = append(output, finalizeCodexThinkingBlock(params)...)
|
||||||
|
params.ThinkingSignature = ""
|
||||||
}
|
}
|
||||||
} else if typeStr == "response.function_call_arguments.delta" {
|
} else if typeStr == "response.function_call_arguments.delta" {
|
||||||
params.HasReceivedArgumentsDelta = true
|
params.HasReceivedArgumentsDelta = true
|
||||||
@@ -389,7 +392,6 @@ func ClaudeTokenCount(_ context.Context, count int64) []byte {
|
|||||||
|
|
||||||
func finalizeCodexThinkingBlock(params *ConvertCodexResponseToClaudeParams) []byte {
|
func finalizeCodexThinkingBlock(params *ConvertCodexResponseToClaudeParams) []byte {
|
||||||
if !params.ThinkingBlockOpen {
|
if !params.ThinkingBlockOpen {
|
||||||
params.ThinkingSignature = ""
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,7 +410,6 @@ func finalizeCodexThinkingBlock(params *ConvertCodexResponseToClaudeParams) []by
|
|||||||
params.BlockIndex++
|
params.BlockIndex++
|
||||||
params.ThinkingBlockOpen = false
|
params.ThinkingBlockOpen = false
|
||||||
params.ThinkingStopPending = false
|
params.ThinkingStopPending = false
|
||||||
params.ThinkingSignature = ""
|
|
||||||
|
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,6 +163,86 @@ func TestConvertCodexResponseToClaude_StreamThinkingFinalizesPendingBlockBeforeN
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConvertCodexResponseToClaude_StreamThinkingRetainsSignatureAcrossMultipartReasoning(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
originalRequest := []byte(`{"messages":[]}`)
|
||||||
|
var param any
|
||||||
|
|
||||||
|
chunks := [][]byte{
|
||||||
|
[]byte("data: {\"type\":\"response.output_item.added\",\"item\":{\"type\":\"reasoning\",\"encrypted_content\":\"enc_sig_multipart\"}}"),
|
||||||
|
[]byte("data: {\"type\":\"response.reasoning_summary_part.added\"}"),
|
||||||
|
[]byte("data: {\"type\":\"response.reasoning_summary_text.delta\",\"delta\":\"First part\"}"),
|
||||||
|
[]byte("data: {\"type\":\"response.reasoning_summary_part.done\"}"),
|
||||||
|
[]byte("data: {\"type\":\"response.reasoning_summary_part.added\"}"),
|
||||||
|
[]byte("data: {\"type\":\"response.reasoning_summary_text.delta\",\"delta\":\"Second part\"}"),
|
||||||
|
[]byte("data: {\"type\":\"response.reasoning_summary_part.done\"}"),
|
||||||
|
[]byte("data: {\"type\":\"response.output_item.done\",\"item\":{\"type\":\"reasoning\"}}"),
|
||||||
|
}
|
||||||
|
|
||||||
|
var outputs [][]byte
|
||||||
|
for _, chunk := range chunks {
|
||||||
|
outputs = append(outputs, ConvertCodexResponseToClaude(ctx, "", originalRequest, nil, chunk, ¶m)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
signatureDeltaCount := 0
|
||||||
|
for _, out := range outputs {
|
||||||
|
for _, line := range strings.Split(string(out), "\n") {
|
||||||
|
if !strings.HasPrefix(line, "data: ") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
data := gjson.Parse(strings.TrimPrefix(line, "data: "))
|
||||||
|
if data.Get("type").String() == "content_block_delta" && data.Get("delta.type").String() == "signature_delta" {
|
||||||
|
signatureDeltaCount++
|
||||||
|
if got := data.Get("delta.signature").String(); got != "enc_sig_multipart" {
|
||||||
|
t.Fatalf("unexpected signature delta: %q", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if signatureDeltaCount != 2 {
|
||||||
|
t.Fatalf("expected signature_delta for both multipart thinking blocks, got %d", signatureDeltaCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConvertCodexResponseToClaude_StreamThinkingUsesEarlyCapturedSignatureWhenDoneOmitsIt(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
originalRequest := []byte(`{"messages":[]}`)
|
||||||
|
var param any
|
||||||
|
|
||||||
|
chunks := [][]byte{
|
||||||
|
[]byte("data: {\"type\":\"response.output_item.added\",\"item\":{\"type\":\"reasoning\",\"encrypted_content\":\"enc_sig_early\"}}"),
|
||||||
|
[]byte("data: {\"type\":\"response.reasoning_summary_part.added\"}"),
|
||||||
|
[]byte("data: {\"type\":\"response.reasoning_summary_text.delta\",\"delta\":\"Let me think\"}"),
|
||||||
|
[]byte("data: {\"type\":\"response.output_item.done\",\"item\":{\"type\":\"reasoning\"}}"),
|
||||||
|
}
|
||||||
|
|
||||||
|
var outputs [][]byte
|
||||||
|
for _, chunk := range chunks {
|
||||||
|
outputs = append(outputs, ConvertCodexResponseToClaude(ctx, "", originalRequest, nil, chunk, ¶m)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
signatureDeltaCount := 0
|
||||||
|
for _, out := range outputs {
|
||||||
|
for _, line := range strings.Split(string(out), "\n") {
|
||||||
|
if !strings.HasPrefix(line, "data: ") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
data := gjson.Parse(strings.TrimPrefix(line, "data: "))
|
||||||
|
if data.Get("type").String() == "content_block_delta" && data.Get("delta.type").String() == "signature_delta" {
|
||||||
|
signatureDeltaCount++
|
||||||
|
if got := data.Get("delta.signature").String(); got != "enc_sig_early" {
|
||||||
|
t.Fatalf("unexpected signature delta: %q", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if signatureDeltaCount != 1 {
|
||||||
|
t.Fatalf("expected signature_delta from early-captured signature, got %d", signatureDeltaCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestConvertCodexResponseToClaudeNonStream_ThinkingIncludesSignature(t *testing.T) {
|
func TestConvertCodexResponseToClaudeNonStream_ThinkingIncludesSignature(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
originalRequest := []byte(`{"messages":[]}`)
|
originalRequest := []byte(`{"messages":[]}`)
|
||||||
|
|||||||
Reference in New Issue
Block a user