unified-agent-api 0.3.5

Agent-agnostic facade and registry for wrapper backends
Documentation
use super::support::*;
use codex::ExecStreamError;

#[test]
fn codex_adapter_implements_backend_harness_adapter_contract() {
    fn assert_impl<T: crate::backend_harness::BackendHarnessAdapter>() {}
    assert_impl::<CodexHarnessAdapter>();
}

#[test]
fn codex_backend_routes_through_harness_and_does_not_reintroduce_orchestration_primitives() {
    const SOURCE: &str = include_str!("../backend.rs");

    assert!(
        SOURCE.contains("run_harnessed_backend("),
        "expected Codex backend to route through the harness entrypoint"
    );
    assert!(
        SOURCE.contains("run_harnessed_backend_control("),
        "expected Codex backend to route cancellation through the harness control entrypoint"
    );
    assert!(
        SOURCE.contains("TerminationState::new"),
        "expected Codex backend control path to register a termination hook"
    );

    assert!(
        !SOURCE.contains("build_gated_run_handle("),
        "expected Codex backend to not bypass harness-owned completion gating"
    );
    assert!(
        !SOURCE.contains("mpsc::channel::<AgentWrapperEvent>(32)"),
        "expected Codex backend to not create a backend-local events channel"
    );
    assert!(
        !SOURCE.contains("tokio::time::timeout("),
        "expected Codex backend to not wrap runs with backend-local timeout orchestration"
    );
}

#[test]
fn codex_backend_mcp_write_hooks_route_through_shared_mcp_runner() {
    const SOURCE: &str = include_str!("../backend.rs");

    assert!(SOURCE.contains("fn mcp_add("));
    assert!(SOURCE.contains("mcp_management::codex_mcp_add_argv"));
    assert!(SOURCE.contains("fn mcp_remove("));
    assert!(SOURCE.contains("mcp_management::codex_mcp_remove_argv"));
    assert!(
        SOURCE.matches("mcp_management::run_codex_mcp(").count() >= 4,
        "expected list/get/add/remove hooks to reuse the shared Codex MCP runner"
    );
}

#[test]
fn codex_downstream_mapping_surfaces_do_not_reopen_raw_add_dirs_parsing() {
    const RAW_KEY: &str = "agent_api.exec.add_dirs.v1";
    const EXEC_SOURCE: &str = include_str!("../exec.rs");
    const FORK_SOURCE: &str = include_str!("../fork.rs");
    const MAPPING_SOURCE: &str = include_str!("../mapping.rs");

    assert!(
        !EXEC_SOURCE.contains(RAW_KEY),
        "expected exec.rs to consume policy.add_dirs without raw add-dir key parsing"
    );
    assert!(
        !FORK_SOURCE.contains(RAW_KEY),
        "expected fork.rs to avoid reopening raw add-dir payload parsing"
    );
    assert!(
        !MAPPING_SOURCE.contains(RAW_KEY),
        "expected mapping.rs to avoid reopening raw add-dir payload parsing"
    );
}

#[test]
fn redact_exec_stream_error_does_not_leak_raw_jsonl_line() {
    let secret = "RAW-LINE-SECRET-DO-NOT-LEAK";
    let err = ExecStreamError::Normalize {
        line: secret.to_string(),
        message: "missing required context".to_string(),
    };

    let redacted = redact_exec_stream_error(&err);
    assert!(!redacted.contains(secret));
    assert!(redacted.contains("line_bytes="));
}

#[test]
fn codex_add_dirs_runtime_rejection_classifier_requires_exact_safe_message_match() {
    assert!(super::super::is_add_dirs_runtime_rejection_signal(
        super::super::PINNED_ADD_DIRS_RUNTIME_REJECTION
    ));
}

#[test]
fn codex_add_dirs_runtime_rejection_classifier_does_not_match_generic_or_prefixed_messages() {
    assert!(!super::super::is_add_dirs_runtime_rejection_signal(
        "codex generic failure"
    ));
    assert!(!super::super::is_add_dirs_runtime_rejection_signal(
        "prefix add_dirs rejected by runtime"
    ));
}

#[test]
fn codex_model_runtime_rejection_classifier_requires_explicit_code() {
    assert!(super::super::exec::is_model_runtime_rejection_signal(Some(
        "model_runtime_rejection"
    )));
}

#[test]
fn codex_model_runtime_rejection_classifier_does_not_match_short_model_substrings() {
    assert!(!super::super::exec::is_model_runtime_rejection_signal(None));
    assert!(!super::super::exec::is_model_runtime_rejection_signal(
        Some("transport_error")
    ));
}