@@ -32,6 +32,7 @@ type claudeToResponsesState struct {
3232 ReasoningActive bool
3333 ReasoningItemID string
3434 ReasoningBuf strings.Builder
35+ ReasoningSignature string
3536 ReasoningPartAdded bool
3637 ReasoningIndex int
3738 // usage aggregation
@@ -89,6 +90,7 @@ func ConvertClaudeResponseToOpenAIResponses(ctx context.Context, modelName strin
8990 st .CurrentMsgID = ""
9091 st .CurrentFCID = ""
9192 st .ReasoningItemID = ""
93+ st .ReasoningSignature = ""
9294 st .ReasoningIndex = 0
9395 st .ReasoningPartAdded = false
9496 st .FuncArgsBuf = make (map [int ]* strings.Builder )
@@ -163,11 +165,16 @@ func ConvertClaudeResponseToOpenAIResponses(ctx context.Context, modelName strin
163165 st .ReasoningActive = true
164166 st .ReasoningIndex = idx
165167 st .ReasoningBuf .Reset ()
168+ st .ReasoningSignature = ""
169+ if signature := cb .Get ("signature" ); signature .Exists () && signature .String () != "" {
170+ st .ReasoningSignature = signature .String ()
171+ }
166172 st .ReasoningItemID = fmt .Sprintf ("rs_%s_%d" , st .ResponseID , idx )
167- item := []byte (`{"type":"response.output_item.added","sequence_number":0,"output_index":0,"item":{"id":"","type":"reasoning","status":"in_progress","summary":[]}}` )
173+ item := []byte (`{"type":"response.output_item.added","sequence_number":0,"output_index":0,"item":{"id":"","type":"reasoning","status":"in_progress","encrypted_content":""," summary":[]}}` )
168174 item , _ = sjson .SetBytes (item , "sequence_number" , nextSeq ())
169175 item , _ = sjson .SetBytes (item , "output_index" , idx )
170176 item , _ = sjson .SetBytes (item , "item.id" , st .ReasoningItemID )
177+ item , _ = sjson .SetBytes (item , "item.encrypted_content" , st .ReasoningSignature )
171178 out = append (out , emitEvent ("response.output_item.added" , item ))
172179 // add a summary part placeholder
173180 part := []byte (`{"type":"response.reasoning_summary_part.added","sequence_number":0,"item_id":"","output_index":0,"summary_index":0,"part":{"type":"summary_text","text":""}}` )
@@ -220,6 +227,12 @@ func ConvertClaudeResponseToOpenAIResponses(ctx context.Context, modelName strin
220227 out = append (out , emitEvent ("response.reasoning_summary_text.delta" , msg ))
221228 }
222229 }
230+ } else if dt == "signature_delta" {
231+ if st .ReasoningActive {
232+ if signature := d .Get ("signature" ); signature .Exists () && signature .String () != "" {
233+ st .ReasoningSignature = signature .String ()
234+ }
235+ }
223236 }
224237 case "content_block_stop" :
225238 idx := int (root .Get ("index" ).Int ())
@@ -277,6 +290,17 @@ func ConvertClaudeResponseToOpenAIResponses(ctx context.Context, modelName strin
277290 partDone , _ = sjson .SetBytes (partDone , "output_index" , st .ReasoningIndex )
278291 partDone , _ = sjson .SetBytes (partDone , "part.text" , full )
279292 out = append (out , emitEvent ("response.reasoning_summary_part.done" , partDone ))
293+ itemDone := []byte (`{"type":"response.output_item.done","sequence_number":0,"output_index":0,"item":{"id":"","type":"reasoning","encrypted_content":"","summary":[]}}` )
294+ itemDone , _ = sjson .SetBytes (itemDone , "sequence_number" , nextSeq ())
295+ itemDone , _ = sjson .SetBytes (itemDone , "item.id" , st .ReasoningItemID )
296+ itemDone , _ = sjson .SetBytes (itemDone , "output_index" , st .ReasoningIndex )
297+ itemDone , _ = sjson .SetBytes (itemDone , "item.encrypted_content" , st .ReasoningSignature )
298+ if full != "" {
299+ summary := []byte (`{"type":"summary_text","text":""}` )
300+ summary , _ = sjson .SetBytes (summary , "text" , full )
301+ itemDone , _ = sjson .SetRawBytes (itemDone , "item.summary.-1" , summary )
302+ }
303+ out = append (out , emitEvent ("response.output_item.done" , itemDone ))
280304 st .ReasoningActive = false
281305 st .ReasoningPartAdded = false
282306 }
@@ -367,10 +391,15 @@ func ConvertClaudeResponseToOpenAIResponses(ctx context.Context, modelName strin
367391 // Build response.output from aggregated state
368392 outputsWrapper := []byte (`{"arr":[]}` )
369393 // reasoning item (if any)
370- if st .ReasoningBuf .Len () > 0 || st .ReasoningPartAdded {
371- item := []byte (`{"id":"","type":"reasoning","summary":[{"type":"summary_text","text":""} ]}` )
394+ if st .ReasoningBuf .Len () > 0 || st .ReasoningPartAdded || st . ReasoningSignature != "" {
395+ item := []byte (`{"id":"","type":"reasoning","encrypted_content":"","summary":[ ]}` )
372396 item , _ = sjson .SetBytes (item , "id" , st .ReasoningItemID )
373- item , _ = sjson .SetBytes (item , "summary.0.text" , st .ReasoningBuf .String ())
397+ item , _ = sjson .SetBytes (item , "encrypted_content" , st .ReasoningSignature )
398+ if st .ReasoningBuf .Len () > 0 {
399+ summary := []byte (`{"type":"summary_text","text":""}` )
400+ summary , _ = sjson .SetBytes (summary , "text" , st .ReasoningBuf .String ())
401+ item , _ = sjson .SetRawBytes (item , "summary.-1" , summary )
402+ }
374403 outputsWrapper , _ = sjson .SetRawBytes (outputsWrapper , "arr.-1" , item )
375404 }
376405 // assistant message item (if any text)
@@ -476,6 +505,7 @@ func ConvertClaudeResponseToOpenAIResponsesNonStream(_ context.Context, _ string
476505 reasoningBuf strings.Builder
477506 reasoningActive bool
478507 reasoningItemID string
508+ reasoningSig string
479509 inputTokens int64
480510 outputTokens int64
481511 )
@@ -525,6 +555,10 @@ func ConvertClaudeResponseToOpenAIResponsesNonStream(_ context.Context, _ string
525555 case "thinking" :
526556 reasoningActive = true
527557 reasoningItemID = fmt .Sprintf ("rs_%s_%d" , responseID , idx )
558+ reasoningSig = ""
559+ if signature := cb .Get ("signature" ); signature .Exists () && signature .String () != "" {
560+ reasoningSig = signature .String ()
561+ }
528562 }
529563
530564 case "content_block_delta" :
@@ -552,6 +586,12 @@ func ConvertClaudeResponseToOpenAIResponsesNonStream(_ context.Context, _ string
552586 reasoningBuf .WriteString (t .String ())
553587 }
554588 }
589+ case "signature_delta" :
590+ if reasoningActive {
591+ if signature := d .Get ("signature" ); signature .Exists () && signature .String () != "" {
592+ reasoningSig = signature .String ()
593+ }
594+ }
555595 }
556596
557597 case "content_block_stop" :
@@ -637,10 +677,15 @@ func ConvertClaudeResponseToOpenAIResponsesNonStream(_ context.Context, _ string
637677
638678 // Build output array
639679 outputsWrapper := []byte (`{"arr":[]}` )
640- if reasoningBuf .Len () > 0 {
641- item := []byte (`{"id":"","type":"reasoning","summary":[{"type":"summary_text","text":""} ]}` )
680+ if reasoningBuf .Len () > 0 || reasoningSig != "" {
681+ item := []byte (`{"id":"","type":"reasoning","encrypted_content":"","summary":[ ]}` )
642682 item , _ = sjson .SetBytes (item , "id" , reasoningItemID )
643- item , _ = sjson .SetBytes (item , "summary.0.text" , reasoningBuf .String ())
683+ item , _ = sjson .SetBytes (item , "encrypted_content" , reasoningSig )
684+ if reasoningBuf .Len () > 0 {
685+ summary := []byte (`{"type":"summary_text","text":""}` )
686+ summary , _ = sjson .SetBytes (summary , "text" , reasoningBuf .String ())
687+ item , _ = sjson .SetRawBytes (item , "summary.-1" , summary )
688+ }
644689 outputsWrapper , _ = sjson .SetRawBytes (outputsWrapper , "arr.-1" , item )
645690 }
646691 if currentMsgID != "" || textBuf .Len () > 0 {
0 commit comments