agent-phone 0.1.0

Minimal sync RPC between two AI agents (Rust port of @p-vbordei/agent-phone). Self-custody keys, Noise-framework handshake, DID-bound WebSocket.
Documentation
use agent_phone::envelope::{decode, encode, Envelope};
use serde_json::{json, Value};

fn envelope_from(fields: Vec<(&str, Value)>) -> Envelope {
    let mut e = Envelope::new();
    for (k, v) in fields {
        e.insert(k.into(), v);
    }
    e
}

#[test]
fn envelope_unary_roundtrip() {
    let env = envelope_from(vec![
        ("stream_id", json!(1)),
        ("type", json!("req")),
        ("seq", json!(0)),
        ("method", json!("echo")),
        ("params", json!({"x": 1})),
    ]);
    let bytes = encode(&env).unwrap();
    let back = decode(&bytes).unwrap();
    assert_eq!(back, env);
}

#[test]
fn envelope_encoding_is_canonical() {
    let a = encode(&envelope_from(vec![
        ("stream_id", json!(1)),
        ("type", json!("req")),
        ("seq", json!(0)),
        ("method", json!("m")),
        ("params", json!({"b": 2, "a": 1})),
    ]))
    .unwrap();
    let b = encode(&envelope_from(vec![
        ("stream_id", json!(1)),
        ("type", json!("req")),
        ("seq", json!(0)),
        ("method", json!("m")),
        ("params", json!({"a": 1, "b": 2})),
    ]))
    .unwrap();
    assert_eq!(a, b);
}

#[test]
fn envelope_rejects_unknown_type() {
    let bad = br#"{"stream_id":1,"type":"bogus","seq":0}"#;
    assert!(decode(bad).is_err());
}