vtcode 0.99.1

A Rust-based terminal coding agent with modular architecture supporting multiple LLM providers
use serde_json::Value;
use vtcode_core::config::constants::tools as tool_names;
use vtcode_core::tools::tool_intent;

pub(crate) fn read_file_path_arg(args: &Value) -> Option<&str> {
    let obj = args.as_object()?;
    for key in ["path", "file_path", "filepath", "target_path"] {
        if let Some(path) = obj.get(key).and_then(Value::as_str) {
            let trimmed = path.trim();
            if !trimmed.is_empty() {
                return Some(trimmed);
            }
        }
    }
    None
}

pub(crate) fn is_read_file_style_call(canonical_tool_name: &str, args: &Value) -> bool {
    match canonical_tool_name {
        tool_names::READ_FILE => true,
        tool_names::UNIFIED_FILE => tool_intent::unified_file_action(args)
            .unwrap_or("read")
            .eq_ignore_ascii_case("read"),
        _ => false,
    }
}

fn looks_like_tool_output_spool_path(path: &str) -> bool {
    let normalized = path.replace('\\', "/");
    normalized.contains(".vtcode/context/tool_outputs/")
}

pub(crate) fn spool_chunk_read_path<'a>(
    canonical_tool_name: &str,
    args: &'a Value,
) -> Option<&'a str> {
    if !is_read_file_style_call(canonical_tool_name, args) {
        return None;
    }

    let path = read_file_path_arg(args)?;
    if looks_like_tool_output_spool_path(path) {
        Some(path)
    } else {
        None
    }
}

#[cfg(test)]
mod tests {
    use serde_json::json;
    use vtcode_core::config::constants::tools;

    use super::spool_chunk_read_path;

    #[test]
    fn spool_chunk_read_path_matches_read_file_spool_reads() {
        let args = json!({
            "path": ".vtcode/context/tool_outputs/unified_exec_123.txt",
            "offset": 41,
            "limit": 40
        });

        assert_eq!(
            spool_chunk_read_path(tools::READ_FILE, &args),
            Some(".vtcode/context/tool_outputs/unified_exec_123.txt")
        );
    }

    #[test]
    fn spool_chunk_read_path_matches_unified_file_read_spool_reads() {
        let args = json!({
            "action": "read",
            "path": ".vtcode/context/tool_outputs/unified_exec_456.txt",
            "offset": 81,
            "limit": 40
        });

        assert_eq!(
            spool_chunk_read_path(tools::UNIFIED_FILE, &args),
            Some(".vtcode/context/tool_outputs/unified_exec_456.txt")
        );
    }

    #[test]
    fn spool_chunk_read_path_ignores_regular_reads() {
        let args = json!({
            "path": "src/main.rs",
            "offset": 1,
            "limit": 100
        });

        assert_eq!(spool_chunk_read_path(tools::READ_FILE, &args), None);
    }

    #[test]
    fn spool_chunk_read_path_ignores_non_read_unified_file_actions() {
        let args = json!({
            "action": "write",
            "path": ".vtcode/context/tool_outputs/unified_exec_789.txt",
            "content": "replacement"
        });

        assert_eq!(spool_chunk_read_path(tools::UNIFIED_FILE, &args), None);
    }
}