gproxy-protocol 1.0.20

Wire-format types and cross-protocol transforms for Claude, OpenAI, and Gemini LLM APIs.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
use std::collections::BTreeMap;

use crate::claude::count_tokens::types as ct;
use crate::claude::create_message::response::ClaudeCreateMessageResponse;
use crate::claude::create_message::types::{BetaServiceTier, BetaStopReason};
use crate::openai::count_tokens::types as ot;
use crate::openai::create_response::response::{OpenAiCreateResponseResponse, ResponseBody};
use crate::openai::create_response::types as rt;
use crate::openai::types::OpenAiResponseHeaders;
use crate::transform::claude::utils::claude_model_to_string;
use crate::transform::openai::generate_content::openai_chat_completions::claude::utils::{
    server_tool_name, stdout_stderr_text,
};
use crate::transform::openai::model_list::claude::utils::openai_error_response_from_claude;
use crate::transform::utils::TransformError;

#[derive(Debug, Clone, Copy)]
enum RecordedCallKind {
    CodeInterpreter,
    WebSearch,
    WebFetch,
    Mcp,
    FileSearch,
}

#[derive(Debug, Clone, Copy)]
struct RecordedCall {
    output_index: usize,
    kind: RecordedCallKind,
}

fn search_queries(input: &ct::JsonObject) -> (Option<String>, Option<Vec<String>>) {
    let queries = input
        .get("queries")
        .and_then(|value| value.as_array())
        .map(|values| {
            values
                .iter()
                .filter_map(|value| value.as_str().map(ToString::to_string))
                .collect::<Vec<_>>()
        })
        .unwrap_or_default();
    let query = input
        .get("query")
        .and_then(|value| value.as_str())
        .map(ToString::to_string)
        .or_else(|| queries.first().cloned());
    let queries = if queries.len() > 1 {
        Some(queries)
    } else {
        None
    };
    (query, queries)
}

impl TryFrom<ClaudeCreateMessageResponse> for OpenAiCreateResponseResponse {
    type Error = TransformError;

    fn try_from(value: ClaudeCreateMessageResponse) -> Result<Self, TransformError> {
        Ok(match value {
            ClaudeCreateMessageResponse::Success {
                stats_code,
                headers,
                body,
            } => {
                let mut output = Vec::new();
                let mut message_content = Vec::new();
                let mut output_text_parts = Vec::new();
                let mut tool_call_count = 0usize;
                let mut recorded_calls = BTreeMap::<String, RecordedCall>::new();

                for (index, block) in body.content.into_iter().enumerate() {
                    match block {
                    crate::claude::create_message::types::BetaContentBlock::Text(block) => {
                        if !block.text.is_empty() {
                            output_text_parts.push(block.text.clone());
                            message_content.push(ot::ResponseOutputContent::Text(
                                ot::ResponseOutputText {
                                    annotations: Vec::new(),
                                    logprobs: None,
                                    text: block.text,
                                    type_: ot::ResponseOutputTextType::OutputText,
                                },
                            ));
                        }
                    }
                    crate::claude::create_message::types::BetaContentBlock::Thinking(block) => {
                        output.push(rt::ResponseOutputItem::ReasoningItem(
                            ot::ResponseReasoningItem {
                                id: Some(format!("reasoning_{index}")),
                                summary: vec![ot::ResponseSummaryTextContent {
                                    text: block.thinking.clone(),
                                    type_: ot::ResponseSummaryTextContentType::SummaryText,
                                }],
                                type_: ot::ResponseReasoningItemType::Reasoning,
                                content: Some(vec![ot::ResponseReasoningTextContent {
                                    text: block.thinking,
                                    type_: ot::ResponseReasoningTextContentType::ReasoningText,
                                }]),
                                encrypted_content: None,
                                status: Some(ot::ResponseItemStatus::Completed),
                            },
                        ));
                    }
                    crate::claude::create_message::types::BetaContentBlock::RedactedThinking(
                        block,
                    ) => {
                        output.push(rt::ResponseOutputItem::ReasoningItem(
                            ot::ResponseReasoningItem {
                                id: Some(format!("redacted_reasoning_{index}")),
                                summary: Vec::new(),
                                type_: ot::ResponseReasoningItemType::Reasoning,
                                content: None,
                                encrypted_content: Some(block.data),
                                status: Some(ot::ResponseItemStatus::Completed),
                            },
                        ));
                    }
                    crate::claude::create_message::types::BetaContentBlock::ToolUse(block) => {
                        tool_call_count += 1;
                        output.push(rt::ResponseOutputItem::FunctionToolCall(
                            ot::ResponseFunctionToolCall {
                                arguments: serde_json::to_string(&block.input)
                                    .unwrap_or_else(|_| "{}".to_string()),
                                call_id: block.id.clone(),
                                name: block.name,
                                type_: ot::ResponseFunctionToolCallType::FunctionCall,
                                id: Some(block.id),
                                status: Some(ot::ResponseItemStatus::Completed),
                            },
                        ));
                    }
                    crate::claude::create_message::types::BetaContentBlock::ServerToolUse(
                        block,
                    ) => {
                        tool_call_count += 1;
                        let call_id = block.id.clone();
                        let output_index = output.len();
                        match block.name {
                            ct::BetaServerToolUseName::CodeExecution => {
                                let code = block
                                    .input
                                    .get("code")
                                    .and_then(|value| value.as_str())
                                    .unwrap_or_default()
                                    .to_string();
                                let container_id = block
                                    .input
                                    .get("container_id")
                                    .and_then(|value| value.as_str())
                                    .unwrap_or_default()
                                    .to_string();
                                output.push(rt::ResponseOutputItem::CodeInterpreterToolCall(
                                    ot::ResponseCodeInterpreterToolCall {
                                        id: call_id.clone(),
                                        code,
                                        container_id,
                                        outputs: None,
                                        status: ot::ResponseCodeInterpreterToolCallStatus::InProgress,
                                        type_: ot::ResponseCodeInterpreterToolCallType::CodeInterpreterCall,
                                    },
                                ));
                                recorded_calls.insert(
                                    call_id,
                                    RecordedCall {
                                        output_index,
                                        kind: RecordedCallKind::CodeInterpreter,
                                    },
                                );
                            }
                            ct::BetaServerToolUseName::WebSearch => {
                                let (query, queries) = search_queries(&block.input);
                                output.push(rt::ResponseOutputItem::FunctionWebSearch(
                                    ot::ResponseFunctionWebSearch {
                                        id: Some(call_id.clone()),
                                        action: ot::ResponseFunctionWebSearchAction::Search {
                                            query,
                                            queries,
                                            sources: None,
                                        },
                                        status: ot::ResponseFunctionWebSearchStatus::Searching,
                                        type_: ot::ResponseFunctionWebSearchType::WebSearchCall,
                                    },
                                ));
                                recorded_calls.insert(
                                    call_id,
                                    RecordedCall {
                                        output_index,
                                        kind: RecordedCallKind::WebSearch,
                                    },
                                );
                            }
                            ct::BetaServerToolUseName::WebFetch => {
                                let url = block
                                    .input
                                    .get("url")
                                    .and_then(|value| value.as_str())
                                    .map(ToString::to_string);
                                output.push(rt::ResponseOutputItem::FunctionWebSearch(
                                    ot::ResponseFunctionWebSearch {
                                        id: Some(call_id.clone()),
                                        action: ot::ResponseFunctionWebSearchAction::OpenPage { url },
                                        status: ot::ResponseFunctionWebSearchStatus::InProgress,
                                        type_: ot::ResponseFunctionWebSearchType::WebSearchCall,
                                    },
                                ));
                                recorded_calls.insert(
                                    call_id,
                                    RecordedCall {
                                        output_index,
                                        kind: RecordedCallKind::WebFetch,
                                    },
                                );
                            }
                            ct::BetaServerToolUseName::BashCodeExecution => {
                                let mut commands = block
                                    .input
                                    .get("commands")
                                    .and_then(|value| value.as_array())
                                    .map(|values| {
                                        values
                                            .iter()
                                            .filter_map(|value| value.as_str().map(ToString::to_string))
                                            .collect::<Vec<_>>()
                                    })
                                    .unwrap_or_default();
                                if commands.is_empty()
                                    && let Some(command) = block
                                        .input
                                        .get("command")
                                        .and_then(|value| value.as_str())
                                {
                                    commands.push(command.to_string());
                                }
                                output.push(rt::ResponseOutputItem::ShellCall(
                                    ot::ResponseShellCall {
                                        action: ot::ResponseShellCallAction {
                                            commands,
                                            max_output_length: None,
                                            timeout_ms: None,
                                        },
                                        call_id,
                                        type_: ot::ResponseShellCallType::ShellCall,
                                        id: Some(block.id),
                                        environment: None,
                                        status: Some(ot::ResponseItemStatus::Completed),
                                    },
                                ));
                            }
                            ct::BetaServerToolUseName::TextEditorCodeExecution => {
                                output.push(rt::ResponseOutputItem::CustomToolCall(
                                    ot::ResponseCustomToolCall {
                                        call_id,
                                        input: serde_json::to_string(&block.input)
                                            .unwrap_or_else(|_| "{}".to_string()),
                                        name: server_tool_name(&block.name),
                                        type_: ot::ResponseCustomToolCallType::CustomToolCall,
                                        id: Some(block.id),
                                    },
                                ));
                            }
                            ct::BetaServerToolUseName::ToolSearchToolRegex
                            | ct::BetaServerToolUseName::ToolSearchToolBm25 => {
                                let queries = block
                                    .input
                                    .get("queries")
                                    .and_then(|value| value.as_array())
                                    .map(|values| {
                                        values
                                            .iter()
                                            .filter_map(|value| value.as_str().map(ToString::to_string))
                                            .collect::<Vec<_>>()
                                    })
                                    .unwrap_or_else(|| {
                                        block
                                            .input
                                            .get("query")
                                            .and_then(|value| value.as_str())
                                            .map(|value| vec![value.to_string()])
                                            .unwrap_or_default()
                                    });
                                output.push(rt::ResponseOutputItem::FileSearchToolCall(
                                    ot::ResponseFileSearchToolCall {
                                        id: call_id.clone(),
                                        queries,
                                        status: ot::ResponseFileSearchToolCallStatus::Searching,
                                        type_: ot::ResponseFileSearchToolCallType::FileSearchCall,
                                        results: None,
                                    },
                                ));
                                recorded_calls.insert(
                                    call_id,
                                    RecordedCall {
                                        output_index,
                                        kind: RecordedCallKind::FileSearch,
                                    },
                                );
                            }
                        }
                    }
                    crate::claude::create_message::types::BetaContentBlock::McpToolUse(block) => {
                        tool_call_count += 1;
                        let output_index = output.len();
                        output.push(rt::ResponseOutputItem::McpCall(ot::ResponseMcpCall {
                            id: block.id.clone(),
                            arguments: serde_json::to_string(&block.input)
                                .unwrap_or_else(|_| "{}".to_string()),
                            name: block.name,
                            server_label: block.server_name,
                            type_: ot::ResponseMcpCallType::McpCall,
                            approval_request_id: None,
                            error: None,
                            output: None,
                            status: Some(ot::ResponseToolCallStatus::Calling),
                        }));
                        recorded_calls.insert(
                            block.id,
                            RecordedCall {
                                output_index,
                                kind: RecordedCallKind::Mcp,
                            },
                        );
                    }
                    crate::claude::create_message::types::BetaContentBlock::McpToolResult(block) => {
                        let is_error = block.is_error.unwrap_or(false);
                        let output_text = match block.content {
                            Some(ct::BetaMcpToolResultBlockParamContent::Text(text)) => text,
                            Some(ct::BetaMcpToolResultBlockParamContent::Blocks(parts)) => parts
                                .into_iter()
                                .map(|part| part.text)
                                .collect::<Vec<_>>()
                                .join("\n"),
                            None => String::new(),
                        };
                        if let Some(record) = recorded_calls.get(&block.tool_use_id)
                            && matches!(record.kind, RecordedCallKind::Mcp)
                            && let Some(rt::ResponseOutputItem::McpCall(call)) =
                                output.get_mut(record.output_index)
                        {
                            call.status = Some(if is_error {
                                ot::ResponseToolCallStatus::Failed
                            } else {
                                ot::ResponseToolCallStatus::Completed
                            });
                            call.error = if is_error {
                                Some(if output_text.is_empty() {
                                    "mcp_tool_result_error".to_string()
                                } else {
                                    output_text.clone()
                                })
                            } else {
                                None
                            };
                            call.output = (!is_error && !output_text.is_empty()).then_some(output_text);
                        } else {
                            output.push(rt::ResponseOutputItem::FunctionCallOutput(
                                ot::ResponseFunctionCallOutput {
                                    call_id: block.tool_use_id,
                                    output: ot::ResponseFunctionCallOutputContent::Text(output_text),
                                    type_: ot::ResponseFunctionCallOutputType::FunctionCallOutput,
                                    id: None,
                                    status: Some(if is_error {
                                        ot::ResponseItemStatus::Incomplete
                                    } else {
                                        ot::ResponseItemStatus::Completed
                                    }),
                                },
                            ));
                        }
                    }
                    crate::claude::create_message::types::BetaContentBlock::Compaction(block) => {
                        output.push(rt::ResponseOutputItem::CompactionItem(
                            ot::ResponseCompactionItemParam {
                                encrypted_content: block.content.unwrap_or_default(),
                                type_: ot::ResponseCompactionItemType::Compaction,
                                id: None,
                                created_by: None,
                            },
                        ));
                    }
                    crate::claude::create_message::types::BetaContentBlock::ContainerUpload(block) => {
                        message_content.push(ot::ResponseOutputContent::Text(
                            ot::ResponseOutputText {
                                annotations: Vec::new(),
                                logprobs: None,
                                text: format!("container_upload:{}", block.file_id),
                                type_: ot::ResponseOutputTextType::OutputText,
                            },
                        ));
                    }
                    crate::claude::create_message::types::BetaContentBlock::WebSearchToolResult(block) => {
                        let status = match block.content {
                            crate::claude::create_message::types::BetaWebSearchToolResultBlockContent::Results(results) => {
                                let sources = results
                                    .into_iter()
                                    .map(|result| ot::ResponseFunctionWebSearchSource {
                                        type_: ot::ResponseFunctionWebSearchSourceType::Url,
                                        url: result.url,
                                    })
                                    .collect::<Vec<_>>();
                                if let Some(record) = recorded_calls.get(&block.tool_use_id)
                                    && matches!(record.kind, RecordedCallKind::WebSearch)
                                    && let Some(rt::ResponseOutputItem::FunctionWebSearch(call)) =
                                        output.get_mut(record.output_index)
                                {
                                    let (query, queries) = match &call.action {
                                        ot::ResponseFunctionWebSearchAction::Search {
                                            query,
                                            queries,
                                            ..
                                        } => (query.clone(), queries.clone()),
                                        _ => (None, None),
                                    };
                                    call.action = ot::ResponseFunctionWebSearchAction::Search {
                                        query,
                                        queries,
                                        sources: (!sources.is_empty()).then_some(sources),
                                    };
                                    call.status = ot::ResponseFunctionWebSearchStatus::Completed;
                                }
                                ot::ResponseFunctionWebSearchStatus::Completed
                            }
                            crate::claude::create_message::types::BetaWebSearchToolResultBlockContent::Error(_) => {
                                if let Some(record) = recorded_calls.get(&block.tool_use_id)
                                    && matches!(record.kind, RecordedCallKind::WebSearch)
                                    && let Some(rt::ResponseOutputItem::FunctionWebSearch(call)) =
                                        output.get_mut(record.output_index)
                                {
                                    call.status = ot::ResponseFunctionWebSearchStatus::Failed;
                                }
                                ot::ResponseFunctionWebSearchStatus::Failed
                            }
                        };
                        if !recorded_calls.contains_key(&block.tool_use_id) {
                            output.push(rt::ResponseOutputItem::FunctionWebSearch(
                                ot::ResponseFunctionWebSearch {
                                    id: Some(block.tool_use_id),
                                    action: ot::ResponseFunctionWebSearchAction::Search {
                                        query: None,
                                        queries: None,
                                        sources: None,
                                    },
                                    status,
                                    type_: ot::ResponseFunctionWebSearchType::WebSearchCall,
                                },
                            ));
                        }
                    }
                    crate::claude::create_message::types::BetaContentBlock::WebFetchToolResult(block) => {
                        match block.content {
                            crate::claude::create_message::types::BetaWebFetchToolResultBlockContent::Result(result) => {
                                if let Some(record) = recorded_calls.get(&block.tool_use_id)
                                    && matches!(record.kind, RecordedCallKind::WebFetch)
                                    && let Some(rt::ResponseOutputItem::FunctionWebSearch(call)) =
                                        output.get_mut(record.output_index)
                                {
                                    call.action = ot::ResponseFunctionWebSearchAction::OpenPage {
                                        url: Some(result.url.clone()),
                                    };
                                    call.status = ot::ResponseFunctionWebSearchStatus::Completed;
                                } else {
                                    output.push(rt::ResponseOutputItem::FunctionWebSearch(
                                        ot::ResponseFunctionWebSearch {
                                            id: Some(block.tool_use_id),
                                            action: ot::ResponseFunctionWebSearchAction::OpenPage {
                                                url: Some(result.url),
                                            },
                                            status: ot::ResponseFunctionWebSearchStatus::Completed,
                                            type_: ot::ResponseFunctionWebSearchType::WebSearchCall,
                                        },
                                    ));
                                }
                            }
                            crate::claude::create_message::types::BetaWebFetchToolResultBlockContent::Error(_) => {
                                if let Some(record) = recorded_calls.get(&block.tool_use_id)
                                    && matches!(record.kind, RecordedCallKind::WebFetch)
                                    && let Some(rt::ResponseOutputItem::FunctionWebSearch(call)) =
                                        output.get_mut(record.output_index)
                                {
                                    call.status = ot::ResponseFunctionWebSearchStatus::Failed;
                                } else {
                                    output.push(rt::ResponseOutputItem::FunctionWebSearch(
                                        ot::ResponseFunctionWebSearch {
                                            id: Some(block.tool_use_id),
                                            action: ot::ResponseFunctionWebSearchAction::OpenPage {
                                                url: None,
                                            },
                                            status: ot::ResponseFunctionWebSearchStatus::Failed,
                                            type_: ot::ResponseFunctionWebSearchType::WebSearchCall,
                                        },
                                    ));
                                }
                            }
                        }
                    }
                    crate::claude::create_message::types::BetaContentBlock::CodeExecutionToolResult(block) => {
                        let (logs, status) = match block.content {
                            ct::BetaCodeExecutionToolResultBlockParamContent::Result(result) => (
                                stdout_stderr_text(result.stdout, result.stderr),
                                ot::ResponseCodeInterpreterToolCallStatus::Completed,
                            ),
                            ct::BetaCodeExecutionToolResultBlockParamContent::Error(err) => (
                                format!("code_execution_error:{:?}", err.error_code),
                                ot::ResponseCodeInterpreterToolCallStatus::Failed,
                            ),
                        };
                        if let Some(record) = recorded_calls.get(&block.tool_use_id)
                            && matches!(record.kind, RecordedCallKind::CodeInterpreter)
                            && let Some(rt::ResponseOutputItem::CodeInterpreterToolCall(call)) =
                                output.get_mut(record.output_index)
                        {
                            call.outputs = (!logs.is_empty()).then_some(vec![
                                ot::ResponseCodeInterpreterOutputItem::Logs { logs },
                            ]);
                            call.status = status;
                        } else {
                            output.push(rt::ResponseOutputItem::CodeInterpreterToolCall(
                                ot::ResponseCodeInterpreterToolCall {
                                    id: block.tool_use_id,
                                    code: String::new(),
                                    container_id: String::new(),
                                    outputs: (!logs.is_empty()).then_some(vec![
                                        ot::ResponseCodeInterpreterOutputItem::Logs { logs },
                                    ]),
                                    status,
                                    type_: ot::ResponseCodeInterpreterToolCallType::CodeInterpreterCall,
                                },
                            ));
                        }
                    }
                    crate::claude::create_message::types::BetaContentBlock::BashCodeExecutionToolResult(block) => {
                        let (stdout, stderr, outcome, status) = match block.content {
                            ct::BetaBashCodeExecutionToolResultBlockParamContent::Result(result) => (
                                result.stdout,
                                result.stderr,
                                ot::ResponseShellCallOutcome::Exit { exit_code: 0 },
                                ot::ResponseItemStatus::Completed,
                            ),
                            ct::BetaBashCodeExecutionToolResultBlockParamContent::Error(err) => (
                                String::new(),
                                format!("bash_code_execution_error:{:?}", err.error_code),
                                if matches!(
                                    err.error_code,
                                    ct::BetaBashCodeExecutionToolResultErrorCode::ExecutionTimeExceeded
                                ) {
                                    ot::ResponseShellCallOutcome::Timeout
                                } else {
                                    ot::ResponseShellCallOutcome::Exit { exit_code: 1 }
                                },
                                ot::ResponseItemStatus::Incomplete,
                            ),
                        };
                        output.push(rt::ResponseOutputItem::ShellCallOutput(
                            ot::ResponseShellCallOutput {
                                call_id: block.tool_use_id,
                                output: vec![ot::ResponseFunctionShellCallOutputContent {
                                    outcome,
                                    stderr,
                                    stdout,
                                }],
                                type_: ot::ResponseShellCallOutputType::ShellCallOutput,
                                id: None,
                                max_output_length: None,
                                status: Some(status),
                            },
                        ));
                    }
                    crate::claude::create_message::types::BetaContentBlock::TextEditorCodeExecutionToolResult(block) => {
                        let text = match block.content {
                            ct::BetaTextEditorCodeExecutionToolResultBlockParamContent::View(view) => {
                                view.content
                            }
                            ct::BetaTextEditorCodeExecutionToolResultBlockParamContent::Create(create) => {
                                format!("file_updated:{}", create.is_file_update)
                            }
                            ct::BetaTextEditorCodeExecutionToolResultBlockParamContent::StrReplace(replace) => {
                                replace.lines.unwrap_or_default().join("\n")
                            }
                            ct::BetaTextEditorCodeExecutionToolResultBlockParamContent::Error(err) => err
                                .error_message
                                .unwrap_or_else(|| {
                                    format!("text_editor_code_execution_error:{:?}", err.error_code)
                                }),
                        };
                        output.push(rt::ResponseOutputItem::CustomToolCallOutput(
                            ot::ResponseCustomToolCallOutput {
                                call_id: block.tool_use_id,
                                output: ot::ResponseCustomToolCallOutputContent::Text(text),
                                type_: ot::ResponseCustomToolCallOutputType::CustomToolCallOutput,
                                id: None,
                            },
                        ));
                    }
                    crate::claude::create_message::types::BetaContentBlock::ToolSearchToolResult(block) => {
                        match block.content {
                            ct::BetaToolSearchToolResultBlockParamContent::Result(result) => {
                                let results = result
                                    .tool_references
                                    .into_iter()
                                    .map(|reference| ot::ResponseFileSearchResult {
                                        filename: Some(reference.tool_name.clone()),
                                        text: Some(reference.tool_name),
                                        ..Default::default()
                                    })
                                    .collect::<Vec<_>>();
                                if let Some(record) = recorded_calls.get(&block.tool_use_id)
                                    && matches!(record.kind, RecordedCallKind::FileSearch)
                                    && let Some(rt::ResponseOutputItem::FileSearchToolCall(call)) =
                                        output.get_mut(record.output_index)
                                {
                                    call.results = Some(results);
                                    call.status = ot::ResponseFileSearchToolCallStatus::Completed;
                                } else {
                                    output.push(rt::ResponseOutputItem::FileSearchToolCall(
                                        ot::ResponseFileSearchToolCall {
                                            id: block.tool_use_id,
                                            queries: Vec::new(),
                                            status: ot::ResponseFileSearchToolCallStatus::Completed,
                                            type_: ot::ResponseFileSearchToolCallType::FileSearchCall,
                                            results: Some(results),
                                        },
                                    ));
                                }
                            }
                            ct::BetaToolSearchToolResultBlockParamContent::Error(err) => {
                                if let Some(record) = recorded_calls.get(&block.tool_use_id)
                                    && matches!(record.kind, RecordedCallKind::FileSearch)
                                    && let Some(rt::ResponseOutputItem::FileSearchToolCall(call)) =
                                        output.get_mut(record.output_index)
                                {
                                    call.status = ot::ResponseFileSearchToolCallStatus::Failed;
                                    call.results = Some(vec![ot::ResponseFileSearchResult {
                                        text: Some(format!("tool_search_error:{:?}", err.error_code)),
                                        ..Default::default()
                                    }]);
                                } else {
                                    output.push(rt::ResponseOutputItem::FileSearchToolCall(
                                        ot::ResponseFileSearchToolCall {
                                            id: block.tool_use_id,
                                            queries: Vec::new(),
                                            status: ot::ResponseFileSearchToolCallStatus::Failed,
                                            type_: ot::ResponseFileSearchToolCallType::FileSearchCall,
                                            results: Some(vec![ot::ResponseFileSearchResult {
                                                text: Some(format!("tool_search_error:{:?}", err.error_code)),
                                                ..Default::default()
                                            }]),
                                        },
                                    ));
                                }
                            }
                        }
                    }
                }
                }

                if !message_content.is_empty() {
                    output.insert(
                        0,
                        rt::ResponseOutputItem::Message(ot::ResponseOutputMessage {
                            id: format!("{}_message_0", body.id),
                            content: message_content,
                            role: ot::ResponseOutputMessageRole::Assistant,
                            phase: Some(ot::ResponseMessagePhase::FinalAnswer),
                            status: Some(ot::ResponseItemStatus::Completed),
                            type_: Some(ot::ResponseOutputMessageType::Message),
                        }),
                    );
                }

                let (status, incomplete_details) = match body.stop_reason {
                    Some(BetaStopReason::MaxTokens)
                    | Some(BetaStopReason::ModelContextWindowExceeded) => (
                        Some(rt::ResponseStatus::Incomplete),
                        Some(rt::ResponseIncompleteDetails {
                            reason: Some(rt::ResponseIncompleteReason::MaxOutputTokens),
                        }),
                    ),
                    Some(BetaStopReason::Refusal) => (
                        Some(rt::ResponseStatus::Incomplete),
                        Some(rt::ResponseIncompleteDetails {
                            reason: Some(rt::ResponseIncompleteReason::ContentFilter),
                        }),
                    ),
                    _ => (Some(rt::ResponseStatus::Completed), None),
                };
                let service_tier = Some(match body.usage.service_tier.clone() {
                    BetaServiceTier::Standard => rt::ResponseServiceTier::Default,
                    BetaServiceTier::Priority => rt::ResponseServiceTier::Priority,
                    BetaServiceTier::Batch => rt::ResponseServiceTier::Flex,
                });
                let input_tokens = body
                    .usage
                    .input_tokens
                    .saturating_add(body.usage.cache_creation_input_tokens)
                    .saturating_add(body.usage.cache_read_input_tokens);
                let usage = Some(rt::ResponseUsage {
                    input_tokens,
                    input_tokens_details: rt::ResponseInputTokensDetails {
                        cached_tokens: body.usage.cache_read_input_tokens,
                    },
                    output_tokens: body.usage.output_tokens,
                    output_tokens_details: rt::ResponseOutputTokensDetails {
                        reasoning_tokens: 0,
                    },
                    total_tokens: input_tokens.saturating_add(body.usage.output_tokens),
                });

                OpenAiCreateResponseResponse::Success {
                    stats_code,
                    headers: OpenAiResponseHeaders {
                        extra: headers.extra,
                    },
                    body: ResponseBody {
                        id: body.id,
                        created_at: 0,
                        error: None,
                        incomplete_details,
                        instructions: Some(ot::ResponseInput::Text(String::new())),
                        metadata: BTreeMap::new(),
                        model: claude_model_to_string(&body.model),
                        object: rt::ResponseObject::Response,
                        output,
                        parallel_tool_calls: tool_call_count > 1,
                        temperature: 1.0,
                        tool_choice: if tool_call_count > 0 {
                            ot::ResponseToolChoice::Options(ot::ResponseToolChoiceOptions::Required)
                        } else {
                            ot::ResponseToolChoice::Options(ot::ResponseToolChoiceOptions::Auto)
                        },
                        tools: Vec::new(),
                        top_p: 1.0,
                        background: None,
                        completed_at: None,
                        conversation: None,
                        max_output_tokens: None,
                        max_tool_calls: None,
                        output_text: if output_text_parts.is_empty() {
                            None
                        } else {
                            Some(output_text_parts.join("\n"))
                        },
                        previous_response_id: None,
                        prompt: None,
                        prompt_cache_key: None,
                        prompt_cache_retention: None,
                        reasoning: None,
                        safety_identifier: None,
                        service_tier,
                        status,
                        text: None,
                        top_logprobs: None,
                        truncation: None,
                        usage,
                        user: None,
                    },
                }
            }
            ClaudeCreateMessageResponse::Error {
                stats_code,
                headers,
                body,
            } => OpenAiCreateResponseResponse::Error {
                stats_code,
                headers: OpenAiResponseHeaders {
                    extra: headers.extra,
                },
                body: openai_error_response_from_claude(stats_code, body),
            },
        })
    }
}