codex-mobile-bridge 0.3.2

Remote bridge and service manager for codex-mobile.
Documentation
use super::*;

#[test]
fn timeline_entry_from_thread_item_infers_low_confidence_semantics_for_responses_calls() {
    let shell_entry = timeline_entry_from_thread_item(
        PRIMARY_RUNTIME_ID,
        "thread-1",
        Some("turn-3"),
        &json!({
            "id": "item-shell",
            "type": "shell_call",
            "call_id": "call-shell",
            "command": "bash -lc 'sed -n \"1,20p\" bridge/src/state/timeline.rs'"
        }),
        "thread_item",
        false,
        true,
    )
    .expect("应创建 shell_call 时间线条目");
    assert_eq!(
        Some("explored"),
        shell_entry
            .metadata
            .get("semantic")
            .and_then(|value| value.get("kind"))
            .and_then(Value::as_str),
    );
    assert_eq!(
        Some("read"),
        shell_entry
            .metadata
            .get("semantic")
            .and_then(|value| value.get("detail"))
            .and_then(Value::as_str),
    );
    assert_eq!(
        Some("low"),
        shell_entry
            .metadata
            .get("semantic")
            .and_then(|value| value.get("confidence"))
            .and_then(Value::as_str),
    );

    let web_search_entry = timeline_entry_from_thread_item(
        PRIMARY_RUNTIME_ID,
        "thread-1",
        Some("turn-3"),
        &json!({
            "id": "item-web-search",
            "type": "web_search_call",
            "call_id": "call-search",
            "query": "Codex CLI TUI"
        }),
        "thread_item",
        false,
        true,
    )
    .expect("应创建 web_search_call 时间线条目");
    assert_eq!(
        Some("explored"),
        web_search_entry
            .metadata
            .get("semantic")
            .and_then(|value| value.get("kind"))
            .and_then(Value::as_str),
    );
    assert_eq!(
        Some("search"),
        web_search_entry
            .metadata
            .get("semantic")
            .and_then(|value| value.get("detail"))
            .and_then(Value::as_str),
    );
    assert_eq!(
        Some("Codex CLI TUI"),
        web_search_entry
            .metadata
            .get("summary")
            .and_then(|value| value.get("query"))
            .and_then(Value::as_str),
    );

    let patch_entry = timeline_entry_from_thread_item(
        PRIMARY_RUNTIME_ID,
        "thread-1",
        Some("turn-3"),
        &json!({
            "id": "item-patch",
            "type": "apply_patch_call",
            "call_id": "call-patch",
            "operation": "*** Begin Patch\n*** Update File: android/app/src/main/java/com/agguy/codexmobile/app/WorkbenchTimeline.kt\n@@\n-old\n+new\n*** End Patch\n"
        }),
        "thread_item",
        false,
        true,
    )
    .expect("应创建 apply_patch_call 时间线条目");
    assert_eq!(
        Some("edited"),
        patch_entry
            .metadata
            .get("semantic")
            .and_then(|value| value.get("kind"))
            .and_then(Value::as_str),
    );
    assert_eq!(
        Some("low"),
        patch_entry
            .metadata
            .get("semantic")
            .and_then(|value| value.get("confidence"))
            .and_then(Value::as_str),
    );
    assert_eq!(
        Some("android/app/src/main/java/com/agguy/codexmobile/app/WorkbenchTimeline.kt"),
        patch_entry
            .metadata
            .get("summary")
            .and_then(|value| value.get("primaryPath"))
            .and_then(Value::as_str),
    );
}

#[test]
fn timeline_entries_from_thread_inherit_semantic_summary_for_output_calls() {
    let thread = json!({
        "id": "thread-1",
        "turns": [
            {
                "id": "turn-4",
                "items": [
                    {
                        "id": "item-shell",
                        "type": "shell_call",
                        "call_id": "call-shell",
                        "command": "bash -lc 'sed -n \"1,20p\" bridge/src/state/timeline.rs'",
                        "status": "completed"
                    },
                    {
                        "id": "item-shell-output",
                        "type": "shell_call_output",
                        "call_id": "call-shell",
                        "output": "line-1\nline-2",
                        "status": "completed"
                    },
                    {
                        "id": "item-patch",
                        "type": "apply_patch_call",
                        "call_id": "call-patch",
                        "operation": "*** Begin Patch\n*** Update File: docs/timeline.md\n@@\n-old\n+new\n*** End Patch\n",
                        "status": "completed"
                    },
                    {
                        "id": "item-patch-output",
                        "type": "apply_patch_call_output",
                        "call_id": "call-patch",
                        "output": "*** Begin Patch\n*** Update File: docs/timeline.md\n@@\n-old\n+new\n*** End Patch\n",
                        "status": "completed"
                    }
                ]
            }
        ]
    });

    let entries = timeline_entries_from_thread(PRIMARY_RUNTIME_ID, &thread)
        .expect("应从 thread 构建时间线条目");

    let shell_output = entries
        .iter()
        .find(|entry| entry.entry_type == "shell_call_output")
        .expect("应存在 shell_call_output");
    assert_eq!(
        Some("explored"),
        shell_output
            .metadata
            .get("semantic")
            .and_then(|value| value.get("kind"))
            .and_then(Value::as_str),
    );
    assert_eq!(
        Some("output"),
        shell_output
            .metadata
            .get("semantic")
            .and_then(|value| value.get("role"))
            .and_then(Value::as_str),
    );
    assert_eq!(
        Some("bash -lc 'sed -n \"1,20p\" bridge/src/state/timeline.rs'"),
        shell_output
            .metadata
            .get("summary")
            .and_then(|value| value.get("command"))
            .and_then(Value::as_str),
    );

    let patch_output = entries
        .iter()
        .find(|entry| entry.entry_type == "apply_patch_call_output")
        .expect("应存在 apply_patch_call_output");
    assert_eq!(
        Some("edited"),
        patch_output
            .metadata
            .get("semantic")
            .and_then(|value| value.get("kind"))
            .and_then(Value::as_str),
    );
    assert_eq!(
        Some("output"),
        patch_output
            .metadata
            .get("semantic")
            .and_then(|value| value.get("role"))
            .and_then(Value::as_str),
    );
    assert_eq!(
        Some("docs/timeline.md"),
        patch_output
            .metadata
            .get("summary")
            .and_then(|value| value.get("primaryPath"))
            .and_then(Value::as_str),
    );
}