vv-agent 0.8.0

VectorVein agent runtime, SDK, CLI, tools, and workspace backends
Documentation
use vv_agent::app_server::protocol::{
    generate_app_server_json_schema_bundle, generate_app_server_typescript_bundle,
};

fn envelope_variants(schema: &str) -> Vec<serde_json::Value> {
    serde_json::from_str::<serde_json::Value>(schema)
        .expect("valid schema")
        .get("oneOf")
        .and_then(serde_json::Value::as_array)
        .expect("oneOf variants")
        .clone()
}

#[test]
fn json_schema_bundle_contains_protocol_envelopes() {
    let bundle = generate_app_server_json_schema_bundle().expect("schema bundle");
    assert!(bundle.contains_key("ClientRequest"));
    assert!(bundle.contains_key("ServerNotification"));
    assert!(bundle.contains_key("ServerRequest"));
    assert!(bundle.contains_key("JsonRpcMessage"));
    assert!(bundle.contains_key("TurnResumeParams"));
    assert!(bundle.contains_key("TurnResumeResponse"));
    let approval = bundle
        .get("ApprovalDecision")
        .expect("approval decision schema");
    for decision in ["allow", "allow_session", "deny", "timeout"] {
        assert!(approval.contains(&format!("\"{decision}\"")));
    }
    let resolve: serde_json::Value = serde_json::from_str(
        bundle
            .get("ApprovalResolveParams")
            .expect("approval resolution schema"),
    )
    .expect("valid approval resolution schema");
    assert_eq!(resolve["properties"]["reason"]["type"], "string");
    assert_eq!(resolve["properties"]["metadata"]["type"], "object");
    assert!(!resolve["required"]
        .as_array()
        .expect("required fields")
        .iter()
        .any(|field| field == "reason" || field == "metadata"));

    let resume: serde_json::Value = serde_json::from_str(
        bundle
            .get("TurnResumeResponse")
            .expect("turn resume response schema"),
    )
    .expect("valid turn resume response schema");
    for sensitive in [
        "runDefinition",
        "runDefinitionDigest",
        "operationArguments",
        "operationResponse",
        "extensionState",
        "idempotencyKey",
    ] {
        assert!(
            !resume["properties"]
                .as_object()
                .expect("resume properties")
                .contains_key(sensitive),
            "sensitive field entered resume schema: {sensitive}"
        );
    }
}

#[test]
fn typescript_bundle_contains_generated_protocol_types() {
    let bundle = generate_app_server_typescript_bundle().expect("typescript bundle");
    assert!(bundle.contains_key("ClientRequest.ts"));
    assert!(bundle.contains_key("ServerNotification.ts"));
    assert!(bundle.contains_key("ServerRequest.ts"));
    assert!(bundle.contains_key("TurnResumeParams.ts"));
    assert!(bundle.contains_key("TurnResumeResponse.ts"));
    assert!(bundle
        .get("ApprovalDecision.ts")
        .expect("approval decision TypeScript")
        .contains("allow_session"));
    let resume = bundle
        .get("TurnResumeResponse.ts")
        .expect("turn resume TypeScript");
    assert!(resume.contains("interface TurnResumeResponse"));
    assert!(resume.contains("method: \"turn/resume\""));
}

#[test]
fn request_schemas_are_real_json_rpc_envelopes() {
    let bundle = generate_app_server_json_schema_bundle().expect("schema bundle");

    for variant in envelope_variants(bundle.get("ClientRequest").expect("client schema")) {
        let properties = variant["properties"].as_object().expect("properties");
        let required = variant["required"].as_array().expect("required");
        assert_eq!(properties["jsonrpc"]["const"], "2.0");
        assert!(required.iter().any(|field| field == "jsonrpc"));
        let method = properties["method"]["const"].as_str().expect("method");
        if method == "initialized" {
            assert!(!properties.contains_key("id"));
        } else {
            assert!(properties.contains_key("id"), "missing id for {method}");
            assert!(required.iter().any(|field| field == "id"));
        }
    }

    for variant in envelope_variants(bundle.get("ServerRequest").expect("server schema")) {
        let properties = variant["properties"].as_object().expect("properties");
        let required = variant["required"].as_array().expect("required");
        assert_eq!(properties["jsonrpc"]["const"], "2.0");
        assert!(properties.contains_key("id"));
        assert!(required.iter().any(|field| field == "jsonrpc"));
        assert!(required.iter().any(|field| field == "id"));
    }
}

#[test]
fn request_typescript_declares_json_rpc_envelopes() {
    let bundle = generate_app_server_typescript_bundle().expect("typescript bundle");
    let client = bundle.get("ClientRequest.ts").expect("client TypeScript");
    let server = bundle.get("ServerRequest.ts").expect("server TypeScript");
    assert!(client.contains("jsonrpc: \"2.0\""));
    assert!(client.contains("id: RequestId"));
    assert!(server.contains("jsonrpc: \"2.0\""));
    assert!(server.contains("id: RequestId"));
}