typeduck-codex-execpolicy 0.6.0

Support package for the standalone Codex Web runtime (codex-core)
Documentation
use codex_protocol::models::FunctionCallOutputBody;
use codex_protocol::models::FunctionCallOutputPayload;
use pretty_assertions::assert_eq;

use super::*;

#[test]
fn preparation_canonicalizes_data_urls_and_rejects_remote_urls() {
    let mut items = vec![ResponseItem::Message {
        id: None,
        role: "user".to_string(),
        content: vec![
            ContentItem::InputAudio {
                audio_url: "data:audio/x-wav;base64,YXVkaW8=".to_string(),
            },
            ContentItem::InputAudio {
                audio_url: "data:audio/ogg;base64,YXVkaW8=".to_string(),
            },
            ContentItem::InputAudio {
                audio_url: "https://example.com/audio.mp3".to_string(),
            },
        ],
        phase: None,
        internal_chat_message_metadata_passthrough: None,
    }];

    prepare_response_items(&mut items);

    assert_eq!(
        items,
        vec![ResponseItem::Message {
            id: None,
            role: "user".to_string(),
            content: vec![
                ContentItem::InputAudio {
                    audio_url: "data:audio/wav;base64,YXVkaW8=".to_string(),
                },
                ContentItem::InputAudio {
                    audio_url: "data:audio/ogg;base64,YXVkaW8=".to_string(),
                },
                ContentItem::InputText {
                    text: "audio content omitted because it could not be processed".to_string(),
                },
            ],
            phase: None,
            internal_chat_message_metadata_passthrough: None,
        }]
    );
}

#[test]
fn preparation_replaces_invalid_message_audio_with_placeholders() {
    let mut items = vec![ResponseItem::Message {
        id: None,
        role: "user".to_string(),
        content: vec![
            ContentItem::InputAudio {
                audio_url: "data:audio/wav;base64,%%%".to_string(),
            },
            ContentItem::InputAudio {
                audio_url: "data:audio/flac;base64,YXVkaW8=".to_string(),
            },
        ],
        phase: None,
        internal_chat_message_metadata_passthrough: None,
    }];

    prepare_response_items(&mut items);

    assert_eq!(
        items,
        vec![ResponseItem::Message {
            id: None,
            role: "user".to_string(),
            content: vec![
                ContentItem::InputText {
                    text: "audio content omitted because it could not be processed".to_string(),
                },
                ContentItem::InputText {
                    text: "audio content omitted because its format is not supported; use wav, mp3, m4a, webm, or ogg".to_string(),
                },
            ],
            phase: None,
            internal_chat_message_metadata_passthrough: None,
        }]
    );
}

#[test]
fn preparation_replaces_only_failed_tool_audio_and_preserves_metadata() {
    let mut items = vec![ResponseItem::FunctionCallOutput {
        id: None,
        call_id: "call-1".to_string(),
        output: FunctionCallOutputPayload {
            body: FunctionCallOutputBody::ContentItems(vec![
                FunctionCallOutputContentItem::InputText {
                    text: "before".to_string(),
                },
                FunctionCallOutputContentItem::InputAudio {
                    audio_url: "data:audio/wav;base64,YXVkaW8=".to_string(),
                },
                FunctionCallOutputContentItem::InputAudio {
                    audio_url: "data:audio/wav,not-base64".to_string(),
                },
            ]),
            success: Some(true),
        },
        internal_chat_message_metadata_passthrough: None,
    }];

    prepare_response_items(&mut items);

    assert_eq!(
        items,
        vec![ResponseItem::FunctionCallOutput {
            id: None,
            call_id: "call-1".to_string(),
            output: FunctionCallOutputPayload {
                body: FunctionCallOutputBody::ContentItems(vec![
                    FunctionCallOutputContentItem::InputText {
                        text: "before".to_string(),
                    },
                    FunctionCallOutputContentItem::InputAudio {
                        audio_url: "data:audio/wav;base64,YXVkaW8=".to_string(),
                    },
                    FunctionCallOutputContentItem::InputText {
                        text: "audio content omitted because it could not be processed".to_string(),
                    },
                ]),
                success: Some(true),
            },
            internal_chat_message_metadata_passthrough: None,
        }]
    );
}

#[test]
fn preparation_errors_map_to_expected_placeholders() {
    let cases = [
        (
            AudioPreparationError::InvalidDataUrl {
                reason: "details remain in logs",
            },
            "audio content omitted because it could not be processed",
        ),
        (
            AudioPreparationError::UnsupportedFormat,
            "audio content omitted because its format is not supported; use wav, mp3, m4a, webm, or ogg",
        ),
        (
            AudioPreparationError::AudioTooLarge { size: usize::MAX },
            "audio content omitted because it exceeded the supported size limit; use a smaller audio file",
        ),
    ];

    for (error, expected) in cases {
        assert_eq!(error.placeholder(), expected);
    }
}