codex-mobile-bridge 0.3.9

Remote bridge and service manager for codex-mobile.
Documentation
use anyhow::Result;
use serde_json::{Value, json};

use crate::state::BridgeState;
use crate::state::helpers::required_string;

pub(super) async fn handle_turn_started(
    state: &BridgeState,
    runtime_id: &str,
    params: Value,
) -> Result<()> {
    let thread_id = required_string(&params, "threadId")?;
    let turn_id = resolve_turn_id(&params).unwrap_or_default();
    state.emit_event(
        "turn/started",
        Some(runtime_id),
        Some(thread_id),
        json!({
            "runtimeId": runtime_id,
            "threadId": thread_id,
            "turnId": turn_id,
            "turn": params.get("turn"),
        }),
    )?;
    Ok(())
}

pub(super) async fn handle_turn_completed(
    state: &BridgeState,
    runtime_id: &str,
    params: Value,
) -> Result<()> {
    let thread_id = required_string(&params, "threadId")?;
    let turn_id = resolve_turn_id(&params).map(ToOwned::to_owned);
    state.emit_event(
        "turn/completed",
        Some(runtime_id),
        Some(thread_id),
        json!({
            "runtimeId": runtime_id,
            "threadId": thread_id,
            "turnId": turn_id,
            "status": params.get("status"),
            "turn": params.get("turn"),
        }),
    )?;
    if let Some(turn_id) = turn_id {
        let _ = state.cleanup_staged_turn_inputs(&turn_id);
    }
    Ok(())
}

fn resolve_turn_id(params: &Value) -> Option<&str> {
    params
        .get("turn")
        .and_then(|turn| turn.get("id"))
        .and_then(Value::as_str)
        .or_else(|| params.get("turnId").and_then(Value::as_str))
}