| 864 | } |
| 865 | |
| 866 | fn reasoning_blocks(event: &TurnEvent) -> Vec<(String, Option<u64>, Option<String>)> { |
| 867 | let Some(raw) = event.raw_json.as_ref() else { |
| 868 | return Vec::new(); |
| 869 | }; |
| 870 | if let Some(blocks) = raw |
| 871 | .get("reasoning_blocks") |
| 872 | .and_then(serde_json::Value::as_array) |
| 873 | { |
| 874 | return blocks |
| 875 | .iter() |
| 876 | .filter_map(|block| { |
| 877 | let text = block.get("text")?.as_str()?.trim(); |
| 878 | if text.is_empty() { |
| 879 | return None; |
| 880 | } |
| 881 | Some(( |
| 882 | text.to_string(), |
| 883 | block.get("duration_ms").and_then(serde_json::Value::as_u64), |
| 884 | block |
| 885 | .get("signature") |
| 886 | .and_then(serde_json::Value::as_str) |
| 887 | .map(ToOwned::to_owned), |
| 888 | )) |
| 889 | }) |
| 890 | .collect(); |
| 891 | } |
| 892 | |
| 893 | let Some(text) = raw |
| 894 | .get("reasoning_text") |
| 895 | .and_then(serde_json::Value::as_str) |
| 896 | else { |
| 897 | return Vec::new(); |
| 898 | }; |
| 899 | let signature = raw |
| 900 | .get("reasoning_signature") |
| 901 | .and_then(serde_json::Value::as_str) |
| 902 | .map(ToOwned::to_owned); |
| 903 | let blocks: Vec<_> = text |
| 904 | .split("\n---\n") |
| 905 | .filter_map(|block| { |
| 906 | let block = block.trim(); |
| 907 | (!block.is_empty()).then(|| block.to_string()) |
| 908 | }) |
| 909 | .collect(); |
| 910 | let last = blocks.len().saturating_sub(1); |
| 911 | blocks |
| 912 | .into_iter() |
| 913 | .enumerate() |
| 914 | .map(|(index, block)| { |
| 915 | let block_signature = (index == last).then(|| signature.clone()).flatten(); |
| 916 | (block, None, block_signature) |
| 917 | }) |
| 918 | .collect() |
| 919 | } |
| 920 | |
| 921 | fn response_text(session: &AgentSession, event: &TurnEvent) -> Option<String> { |
| 922 | let raw = event.raw_json.as_ref(); |