| 685 | } |
| 686 | |
| 687 | fn flatten_system_text_before_cache_control(body: &mut Value) { |
| 688 | canonicalize_claude_body(body); |
| 689 | let Some(blocks) = body.get_mut("system").and_then(Value::as_array_mut) else { |
| 690 | return; |
| 691 | }; |
| 692 | |
| 693 | let mut merge_ranges = Vec::new(); |
| 694 | let mut run_start = None; |
| 695 | let mut run_text = String::new(); |
| 696 | |
| 697 | for (index, block) in blocks.iter().enumerate() { |
| 698 | if is_claudecode_billing_header_block(block) { |
| 699 | run_start = None; |
| 700 | run_text.clear(); |
| 701 | continue; |
| 702 | } |
| 703 | |
| 704 | if block_has_cache_control(block) { |
| 705 | if let Some(start) = run_start.take() |
| 706 | && index.saturating_sub(start) > 1 |
| 707 | { |
| 708 | merge_ranges.push((start, index, std::mem::take(&mut run_text))); |
| 709 | } else { |
| 710 | run_text.clear(); |
| 711 | } |
| 712 | continue; |
| 713 | } |
| 714 | |
| 715 | if let Some(text) = block_text(block) { |
| 716 | if run_start.is_none() { |
| 717 | run_start = Some(index); |
| 718 | } |
| 719 | run_text.push_str(text); |
| 720 | continue; |
| 721 | } |
| 722 | |
| 723 | run_start = None; |
| 724 | run_text.clear(); |
| 725 | } |
| 726 | |
| 727 | for (start, end, text) in merge_ranges.into_iter().rev() { |
| 728 | blocks.splice(start..end, [json_text_block(text.as_str())]); |
| 729 | } |
| 730 | } |
| 731 | |
| 732 | fn build_claudecode_billing_header_text(body: &Value, version: &str) -> String { |
| 733 | let user_text = first_claudecode_user_text(body); |