unified-agent-api 0.3.5

Agent-agnostic facade and registry for wrapper backends
Documentation
use crate::{AgentWrapperEvent, AgentWrapperEventKind, AgentWrapperKind};

use super::{AGENT_KIND, CHANNEL_ASSISTANT, CHANNEL_TOOL};

pub(super) fn map_stream_json_event(
    event: gemini_cli::GeminiStreamJsonEvent,
) -> Vec<AgentWrapperEvent> {
    match event {
        gemini_cli::GeminiStreamJsonEvent::Init {
            session_id,
            model,
            raw,
        } => vec![status_event(
            Some("init".to_string()),
            Some(serde_json::json!({
                "session": { "id": session_id },
                "model": model,
                "raw": raw,
            })),
        )],
        gemini_cli::GeminiStreamJsonEvent::Message {
            role,
            content,
            delta,
            raw,
        } => vec![text_event(
            role.clone(),
            content,
            Some(serde_json::json!({
                "role": role,
                "delta": delta,
                "raw": raw,
            })),
        )],
        gemini_cli::GeminiStreamJsonEvent::ToolUse {
            tool_name,
            tool_id,
            parameters,
            raw,
        } => vec![AgentWrapperEvent {
            agent_kind: AgentWrapperKind(AGENT_KIND.to_string()),
            kind: AgentWrapperEventKind::ToolCall,
            channel: Some(CHANNEL_TOOL.to_string()),
            text: None,
            message: None,
            data: Some(serde_json::json!({
                "tool_name": tool_name,
                "tool_id": tool_id,
                "parameters": parameters,
                "raw": raw,
            })),
        }],
        gemini_cli::GeminiStreamJsonEvent::ToolResult {
            tool_id,
            status,
            output,
            error,
            raw,
        } => vec![AgentWrapperEvent {
            agent_kind: AgentWrapperKind(AGENT_KIND.to_string()),
            kind: AgentWrapperEventKind::ToolResult,
            channel: Some(CHANNEL_TOOL.to_string()),
            text: output,
            message: None,
            data: Some(serde_json::json!({
                "tool_id": tool_id,
                "status": status,
                "error": error,
                "raw": raw,
            })),
        }],
        gemini_cli::GeminiStreamJsonEvent::Error {
            severity,
            message,
            raw,
        } => vec![error_event(
            message,
            Some(serde_json::json!({
                "severity": severity,
                "raw": raw,
            })),
        )],
        gemini_cli::GeminiStreamJsonEvent::Result { payload } => {
            if payload.status == "error" {
                vec![error_event(
                    payload
                        .error_message
                        .unwrap_or_else(|| "result error".to_string()),
                    Some(serde_json::json!({
                        "status": payload.status,
                        "error_type": payload.error_type,
                        "stats": payload.stats,
                        "raw": payload.raw,
                    })),
                )]
            } else {
                vec![status_event(
                    Some("result success".to_string()),
                    Some(serde_json::json!({
                        "status": payload.status,
                        "stats": payload.stats,
                        "raw": payload.raw,
                    })),
                )]
            }
        }
        gemini_cli::GeminiStreamJsonEvent::Unknown { event_type, raw } => vec![AgentWrapperEvent {
            agent_kind: AgentWrapperKind(AGENT_KIND.to_string()),
            kind: AgentWrapperEventKind::Unknown,
            channel: None,
            text: None,
            message: None,
            data: Some(serde_json::json!({
                "event_type": event_type,
                "raw": raw,
            })),
        }],
    }
}

fn status_event(message: Option<String>, data: Option<serde_json::Value>) -> AgentWrapperEvent {
    AgentWrapperEvent {
        agent_kind: AgentWrapperKind(AGENT_KIND.to_string()),
        kind: AgentWrapperEventKind::Status,
        channel: Some("status".to_string()),
        text: None,
        message,
        data,
    }
}

fn text_event(role: String, text: String, data: Option<serde_json::Value>) -> AgentWrapperEvent {
    AgentWrapperEvent {
        agent_kind: AgentWrapperKind(AGENT_KIND.to_string()),
        kind: AgentWrapperEventKind::TextOutput,
        channel: Some(match role.as_str() {
            "assistant" => CHANNEL_ASSISTANT.to_string(),
            other => other.to_string(),
        }),
        text: Some(text),
        message: None,
        data,
    }
}

fn error_event(message: String, data: Option<serde_json::Value>) -> AgentWrapperEvent {
    AgentWrapperEvent {
        agent_kind: AgentWrapperKind(AGENT_KIND.to_string()),
        kind: AgentWrapperEventKind::Error,
        channel: Some("error".to_string()),
        text: None,
        message: Some(message),
        data,
    }
}