rightkit-agent-engine-protocol 0.1.0

Agent engine protocol: events, envelopes, tool calls, trust wrapping and settlement types shared by agent hosts
Documentation
use super::*;

#[test]
fn protocol_event_session_started_kind() {
    let ev = ProtocolEvent::SessionStarted {
        session_id: "s1".into(),
        seq: 1,
        created_at: "t".into(),
        title: None,
    };
    let json = serde_json::to_string(&ev).unwrap();
    assert!(json.contains(r#""$kind":"sessionStarted""#), "got: {json}");
    let rt: ProtocolEvent = serde_json::from_str(&json).unwrap();
    assert!(matches!(rt, ProtocolEvent::SessionStarted { .. }));
}

#[test]
fn protocol_event_session_title_updated_kind() {
    let ev = ProtocolEvent::SessionTitleUpdated {
        session_id: "s1".into(),
        seq: 2,
        created_at: "t".into(),
        title: "Fix Rust Guardrails".into(),
    };
    let json = serde_json::to_string(&ev).unwrap();
    assert!(json.contains(r#""$kind":"sessionTitleUpdated""#));
    assert!(json.contains(r#""title":"Fix Rust Guardrails""#));
    let rt: ProtocolEvent = serde_json::from_str(&json).unwrap();
    assert!(matches!(rt, ProtocolEvent::SessionTitleUpdated { .. }));
}

#[test]
fn protocol_event_meta_accessors_share_common_fields() {
    let ev = ProtocolEvent::ToolApprovalResolved {
        session_id: "s-meta".into(),
        seq: 42,
        created_at: "2026-06-28T00:00:00Z".into(),
        tool_call_id: "tc1".into(),
        approved: true,
    };

    let meta = ev.meta();
    assert_eq!(meta.session_id, "s-meta");
    assert_eq!(meta.seq, 42);
    assert_eq!(meta.created_at, "2026-06-28T00:00:00Z");
    assert_eq!(ev.session_id(), "s-meta");
    assert_eq!(ev.seq(), 42);
    assert_eq!(ev.created_at(), "2026-06-28T00:00:00Z");

    let json = serde_json::to_value(&ev).unwrap();
    assert_eq!(json["sessionId"], "s-meta");
    assert!(json.get("meta").is_none(), "wire shape must stay flat");
}

#[test]
fn protocol_event_assistant_delta_kind() {
    let ev = ProtocolEvent::AssistantDelta {
        session_id: "s1".into(),
        seq: 1,
        created_at: "t".into(),
        text: "hi".into(),
        is_reasoning: false,
    };
    let json = serde_json::to_string(&ev).unwrap();
    assert!(json.contains(r#""$kind":"assistantDelta""#), "got: {json}");
    let rt: ProtocolEvent = serde_json::from_str(&json).unwrap();
    assert!(matches!(rt, ProtocolEvent::AssistantDelta { .. }));
}

#[test]
fn protocol_event_user_message_submitted_nonce_is_optional() {
    let ev = ProtocolEvent::UserMessageSubmitted {
        session_id: "s1".into(),
        seq: 2,
        created_at: "t".into(),
        text: "hello".into(),
        nonce: Some("nonce-123".into()),
        trust: None,
        attachments: Vec::new(),
    };
    let json = serde_json::to_string(&ev).unwrap();
    assert!(
        json.contains(r#""$kind":"userMessageSubmitted""#),
        "got: {json}"
    );
    assert!(json.contains(r#""nonce":"nonce-123""#), "got: {json}");

    let legacy = r#"{"$kind":"userMessageSubmitted","sessionId":"s1","seq":2,"createdAt":"t","text":"hello"}"#;
    let rt: ProtocolEvent = serde_json::from_str(legacy).unwrap();
    assert!(matches!(
        rt,
        ProtocolEvent::UserMessageSubmitted {
            nonce: None,
            attachments,
            ..
        } if attachments.is_empty()
    ));
}

#[test]
fn protocol_event_assistant_message_completed_kind() {
    let ev = ProtocolEvent::AssistantMessageCompleted {
        session_id: "s1".into(),
        seq: 2,
        created_at: "t".into(),
        message: assistant_msg(),
    };
    let json = serde_json::to_string(&ev).unwrap();
    assert!(
        json.contains(r#""$kind":"assistantMessageCompleted""#),
        "got: {json}"
    );
    let rt: ProtocolEvent = serde_json::from_str(&json).unwrap();
    assert!(matches!(
        rt,
        ProtocolEvent::AssistantMessageCompleted { .. }
    ));
}

#[test]
fn protocol_event_tool_call_started_kind() {
    let ev = ProtocolEvent::ToolCallStarted {
        session_id: "s1".into(),
        seq: 3,
        created_at: "t".into(),
        call: make_tool_call(),
    };
    let json = serde_json::to_string(&ev).unwrap();
    assert!(json.contains(r#""$kind":"toolCallStarted""#), "got: {json}");
    let rt: ProtocolEvent = serde_json::from_str(&json).unwrap();
    assert!(matches!(rt, ProtocolEvent::ToolCallStarted { .. }));
}

#[test]
fn protocol_event_tool_approval_requested_kind() {
    let ev = ProtocolEvent::ToolApprovalRequested {
        session_id: "s1".into(),
        seq: 4,
        created_at: "t".into(),
        call: ToolCall {
            id: "tc1".into(),
            name: "write_file".into(),
            arguments_json: "{}".into(),
        },
        risk_label: "high".into(),
        proposed_change: Some("+ foo".into()),
        policy_source: None,
        middleware_decisions: vec![MiddlewareDecisionEvidence {
            middleware_id: "builtin.observe-approvals".into(),
            title: "Observe approvals".into(),
            phase: "approvalRequested".into(),
            effect: "observe".into(),
            decision: "emitObservation".into(),
            reason: "Approval prompt emitted".into(),
        }],
    };
    let json = serde_json::to_string(&ev).unwrap();
    assert!(
        json.contains(r#""$kind":"toolApprovalRequested""#),
        "got: {json}"
    );
    assert!(json.contains(r#""middlewareDecisions""#), "got: {json}");
    let rt: ProtocolEvent = serde_json::from_str(&json).unwrap();
    assert!(matches!(rt, ProtocolEvent::ToolApprovalRequested { .. }));
}

#[test]
fn protocol_event_tool_approval_resolved_kind() {
    let ev = ProtocolEvent::ToolApprovalResolved {
        session_id: "s1".into(),
        seq: 5,
        created_at: "t".into(),
        tool_call_id: "tc1".into(),
        approved: true,
    };
    let json = serde_json::to_string(&ev).unwrap();
    assert!(
        json.contains(r#""$kind":"toolApprovalResolved""#),
        "got: {json}"
    );
    let rt: ProtocolEvent = serde_json::from_str(&json).unwrap();
    assert!(matches!(rt, ProtocolEvent::ToolApprovalResolved { .. }));
}

#[test]
fn protocol_event_tool_result_added_kind() {
    let ev = ProtocolEvent::ToolResultAdded {
        session_id: "s1".into(),
        seq: 6,
        created_at: "t".into(),
        result: tool_result_msg(),
    };
    let json = serde_json::to_string(&ev).unwrap();
    assert!(json.contains(r#""$kind":"toolResultAdded""#), "got: {json}");
    let rt: ProtocolEvent = serde_json::from_str(&json).unwrap();
    assert!(matches!(rt, ProtocolEvent::ToolResultAdded { .. }));
}

#[test]
fn protocol_event_verification_finished_kind() {
    let ev = ProtocolEvent::VerificationFinished {
        session_id: "s1".into(),
        seq: 7,
        created_at: "t".into(),
        summary: "all good".into(),
        passed: true,
        tool: "cargo test".into(),
        issue_count: 0,
        issues: vec![],
    };
    let json = serde_json::to_string(&ev).unwrap();
    assert!(
        json.contains(r#""$kind":"verificationFinished""#),
        "got: {json}"
    );
    let rt: ProtocolEvent = serde_json::from_str(&json).unwrap();
    assert!(matches!(rt, ProtocolEvent::VerificationFinished { .. }));
}