liminal-cli 0.3.1

The liminal command: serve the network, maintain its stores, or serve its discovery MCP over stdio
Documentation
//! Send contracts cross a real exchange and receive through the real SDK.

use super::channel_test_support::{TestResult, require, run};
use super::channel_wire_test_support::Publisher;
use liminal::protocol::Frame;
use liminal_sdk::{SubscriptionStream, lys_pass_credential};
use serde_json::json;

#[test]
fn agt001_send_schema_has_only_subject_text_and_optional_key() -> TestResult {
    run(|_, host| {
        host.initialize()?;
        let listed = host.request("tools/list", &json!({}))?;
        let tools = listed["result"]["tools"]
            .as_array()
            .ok_or("tools/list has no tools")?;
        let tool = tools
            .iter()
            .find(|tool| tool["name"] == "send")
            .ok_or("the send tool is missing")?;
        let schema = &tool["inputSchema"];
        require(
            schema["required"] == json!(["subject", "text"]),
            "send requires subject and text",
        )?;
        require(
            schema["properties"]
                .as_object()
                .is_some_and(|fields| fields.len() == 3),
            "send must expose exactly three arguments",
        )?;
        for field in ["subject", "text", "key"] {
            require(
                schema["properties"][field]["type"] == "string",
                "every send argument is a string",
            )?;
        }
        require(
            schema["additionalProperties"] == false,
            "send must refuse unknown arguments",
        )
    })
}

#[test]
fn agt001_send_preserves_raw_text_and_returns_the_ack_id() -> TestResult {
    run(|exchange, host| {
        host.initialize()?;
        let credential = lys_pass_credential(&exchange.pass("beta")?);
        let stream = SubscriptionStream::open_with_auth(
            &exchange.address,
            "agents.beta.inbox",
            Vec::new(),
            &credential,
        )?;
        let text = "{\"text\":\"alpha to beta\"}\r\n";
        let answer = host.tool(
            "send",
            &json!({"subject":"agents.beta.inbox","text":text,"key":"first"}),
        )?;
        if answer["isError"] != false {
            return Err(format!("a granted send must succeed: {answer}").into());
        }
        let data = &answer["structuredContent"];
        require(
            data["subject"] == "agents.beta.inbox",
            "send must name its subject",
        )?;
        let id = data.get("id").ok_or("send must return the PublishAck id")?;
        let delivered = stream.recv()?;
        require(
            delivered.payload() == text.as_bytes(),
            "send must publish text bytes without JSON wrapping",
        )?;
        let message = delivered
            .message()
            .ok_or("delivery must carry the original server id")?;
        require(
            *id == json!(message.id),
            "send must return the original PublishAck id without inventing one",
        )
    })
}

#[test]
fn agt001_ungranted_send_returns_the_real_publish_refusal_verbatim() -> TestResult {
    run(|exchange, host| {
        host.initialize()?;
        let credential = lys_pass_credential(&exchange.pass("alpha")?);
        let mut publisher = Publisher::connect(&exchange.address, &credential)?;
        let Frame::PublishError {
            message: Some(words),
            ..
        } = publisher.publish("agents.ungranted.inbox", b"{}".to_vec())?
        else {
            return Err("the real server must return a named publish refusal".into());
        };
        let answer = host.tool(
            "send",
            &json!({"subject":"agents.ungranted.inbox","text":"{}","key":"refused"}),
        )?;
        require(answer["isError"] == true, "an ungranted send must fail")?;
        require(
            answer["structuredContent"]["subject"] == "agents.ungranted.inbox",
            "send must name the refused subject",
        )?;
        require(
            answer["structuredContent"]["error"] == words,
            "send must preserve the server's refusal verbatim",
        )?;
        require(
            answer["content"][0]["text"] == words,
            "the text result must preserve the same server words",
        )
    })
}

#[test]
fn agt001_repeated_key_delivers_once_before_a_distinct_marker() -> TestResult {
    run(|exchange, host| {
        host.initialize()?;
        let credential = lys_pass_credential(&exchange.pass("beta")?);
        let stream = SubscriptionStream::open_with_auth(
            &exchange.address,
            "agents.beta.inbox",
            Vec::new(),
            &credential,
        )?;
        let arguments =
            json!({"subject":"agents.beta.inbox","text":"{\"text\":\"same\"}","key":"same"});
        let first = host.tool("send", &arguments)?;
        let second = host.tool("send", &arguments)?;
        require(
            first["isError"] == false && second["isError"] == false,
            "both same-key sends must answer their ack",
        )?;
        let marker = host.tool(
            "send",
            &json!({"subject":"agents.beta.inbox","text":"{\"text\":\"marker\"}","key":"distinct"}),
        )?;
        require(
            marker["isError"] == false,
            "the distinct marker must be accepted",
        )?;
        require(
            stream.recv()?.payload() == b"{\"text\":\"same\"}",
            "the first delivery must be the first publish",
        )?;
        require(
            stream.recv()?.payload() == b"{\"text\":\"marker\"}",
            "the next delivery must be the marker, with no duplicate between",
        )
    })
}

#[test]
fn agt001_oversize_send_is_refused_without_a_connection() -> TestResult {
    run(|exchange, host| {
        host.initialize()?;
        let before = exchange.supervisor.active_connection_count();
        let answer = host.tool(
            "send",
            &json!({"subject":"agents.beta.inbox","text":"x".repeat(65537)}),
        )?;
        require(answer["isError"] == true, "oversize text must be refused")?;
        require(
            answer["structuredContent"]["error"] == "text is 65537 bytes; the bound is 65536",
            "oversize text must name its exact size and configured bound",
        )?;
        require(
            exchange.supervisor.active_connection_count() == before,
            "an oversize send must leave the server connection count unchanged",
        )
    })
}