vv-agent 0.4.1

VectorVein agent runtime, SDK, CLI, tools, and workspace backends
Documentation
use std::fs;
use std::io::{BufRead, BufReader, Write};
use std::process::{Command, Stdio};

use vv_agent::cli::{
    parse_cli_args_from_with_default_settings, parse_cli_command_from_with_default_settings,
    AppServerCliCommand, CliCommand, DebugCliCommand,
};

#[test]
fn cli_parses_app_server_stdio_command() {
    let command = parse_cli_command_from_with_default_settings(
        ["vv-agent", "app-server", "--listen", "stdio"],
        "local_settings.json",
    )
    .expect("parse command");

    assert_eq!(
        command,
        CliCommand::AppServer(AppServerCliCommand::ListenStdio)
    );
}

#[test]
fn cli_parses_app_server_schema_generation_commands() {
    let ts = parse_cli_command_from_with_default_settings(
        [
            "vv-agent",
            "app-server",
            "generate-ts",
            "--out",
            "target/app-server-schema/typescript",
        ],
        "local_settings.json",
    )
    .expect("parse ts command");
    assert_eq!(
        ts,
        CliCommand::AppServer(AppServerCliCommand::GenerateTs {
            out: "target/app-server-schema/typescript".into()
        })
    );

    let json = parse_cli_command_from_with_default_settings(
        [
            "vv-agent",
            "app-server",
            "generate-json-schema",
            "--out",
            "target/app-server-schema/json",
        ],
        "local_settings.json",
    )
    .expect("parse json command");
    assert_eq!(
        json,
        CliCommand::AppServer(AppServerCliCommand::GenerateJsonSchema {
            out: "target/app-server-schema/json".into()
        })
    );
}

#[test]
fn cli_parses_debug_app_server_send_message_command() {
    let command = parse_cli_command_from_with_default_settings(
        ["vv-agent", "debug", "app-server", "send-message", "hello"],
        "local_settings.json",
    )
    .expect("parse debug command");

    assert_eq!(
        command,
        CliCommand::Debug(DebugCliCommand::AppServerSendMessage {
            message: "hello".to_string()
        })
    );
}

#[test]
fn existing_prompt_cli_parse_still_works() {
    let args = parse_cli_args_from_with_default_settings(
        ["vv-agent", "--prompt", "finish this"],
        "local_settings.json",
    )
    .expect("parse prompt");

    assert_eq!(args.prompt, "finish this");
}

#[test]
fn cli_schema_generation_writes_json_and_typescript_files() {
    let tempdir = tempfile::tempdir().expect("tempdir");
    let json_out = tempdir.path().join("json");
    let ts_out = tempdir.path().join("typescript");

    let json_status = Command::new(env!("CARGO_BIN_EXE_vv-agent"))
        .args([
            "app-server",
            "generate-json-schema",
            "--out",
            json_out.to_str().expect("json path"),
        ])
        .status()
        .expect("run json schema command");
    assert!(json_status.success());
    assert!(json_out.join("ClientRequest.json").exists());
    assert!(json_out.join("ServerNotification.json").exists());
    assert!(json_out.join("ServerRequest.json").exists());
    assert!(json_out.join("JsonRpcMessage.json").exists());

    let ts_status = Command::new(env!("CARGO_BIN_EXE_vv-agent"))
        .args([
            "app-server",
            "generate-ts",
            "--out",
            ts_out.to_str().expect("ts path"),
        ])
        .status()
        .expect("run ts command");
    assert!(ts_status.success());
    assert!(ts_out.join("ClientRequest.ts").exists());
    assert!(ts_out.join("ServerNotification.ts").exists());
    assert!(ts_out.join("ServerRequest.ts").exists());

    let client_request =
        fs::read_to_string(json_out.join("ClientRequest.json")).expect("schema file");
    assert!(client_request.contains("thread/start"));
}

#[test]
fn cli_app_server_stdio_can_be_spawned_and_initialized() {
    let mut child = Command::new(env!("CARGO_BIN_EXE_vv-agent"))
        .args(["app-server", "--listen", "stdio"])
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .spawn()
        .expect("spawn app server");

    {
        let stdin = child.stdin.as_mut().expect("stdin");
        writeln!(
            stdin,
            "{}",
            serde_json::json!({
                "id": 1,
                "method": "initialize",
                "params": {
                    "clientInfo": {"name": "stdio-test"},
                    "capabilities": {}
                }
            })
        )
        .expect("write initialize");
    }

    let mut stdout = BufReader::new(child.stdout.take().expect("stdout"));
    let mut line = String::new();
    stdout.read_line(&mut line).expect("read response");
    child.kill().ok();
    let _ = child.wait();

    let response: serde_json::Value = serde_json::from_str(&line).expect("json response");
    assert_eq!(response["id"], 1);
    assert_eq!(response["result"]["serverInfo"]["name"], "vv-agent-rs");
}

#[test]
fn cli_debug_app_server_send_message_runs_scripted_turn() {
    let output = Command::new(env!("CARGO_BIN_EXE_vv-agent"))
        .args(["debug", "app-server", "send-message", "hello"])
        .output()
        .expect("run debug command");

    assert!(
        output.status.success(),
        "stderr: {}",
        String::from_utf8_lossy(&output.stderr)
    );
    let stdout = String::from_utf8_lossy(&output.stdout);
    assert!(stdout.contains("hello"));
    assert!(stdout.contains("turn/completed"));
}