rho-coding-agent 1.17.0

A lightweight agent harness inspired by Pi
Documentation
use pretty_assertions::assert_eq;
use serde_json::json;

use super::*;

#[test]
fn store_and_load_round_trip_under_data_root() {
    let root = tempfile::tempdir().unwrap();
    let store = WebAccessStore::with_root(root.path().to_path_buf());
    let response_id = new_response_id();

    store
        .store(
            response_id.clone(),
            StoredContent {
                kind: "fetch_content".into(),
                items: vec![StoredItem {
                    url: Some("https://example.com".into()),
                    query: None,
                    title: Some("Example".into()),
                    content: "hello body".into(),
                    metadata: json!({"mode": "http_fetch"}),
                }],
            },
        )
        .unwrap();

    let path = root
        .path()
        .join("content")
        .join(format!("{response_id}.json"));
    assert!(path.is_file());

    let loaded = store.load(&response_id).unwrap();
    assert_eq!(loaded.kind, "fetch_content");
    assert_eq!(loaded.items[0].content, "hello body");
}

#[test]
fn load_falls_back_to_legacy_temp_cache() {
    let root = tempfile::tempdir().unwrap();
    let store = WebAccessStore::with_root(root.path().to_path_buf());
    let response_id = new_response_id();

    let legacy_dir = std::env::temp_dir().join("rho-web-access").join("content");
    fs::create_dir_all(&legacy_dir).unwrap();
    let legacy_path = legacy_dir.join(format!("{response_id}.json"));
    let payload = StoredContent {
        kind: "fetch_content".into(),
        items: vec![StoredItem {
            url: Some("https://legacy.example".into()),
            query: None,
            title: None,
            content: "legacy body".into(),
            metadata: json!({}),
        }],
    };
    fs::write(&legacy_path, serde_json::to_string(&payload).unwrap()).unwrap();

    let loaded = store.load(&response_id).unwrap();
    assert_eq!(loaded.items[0].content, "legacy body");
    let _ = fs::remove_file(legacy_path);
}

#[test]
fn unreadable_stored_blob_reports_the_read_failure() {
    let root = tempfile::tempdir().unwrap();
    let store = WebAccessStore::with_root(root.path().to_path_buf());
    let response_id = new_response_id();
    // A directory in the blob's place fails to read for a reason other than
    // "missing", so the legacy fallback must not hide it.
    fs::create_dir_all(
        root.path()
            .join("content")
            .join(format!("{response_id}.json")),
    )
    .unwrap();

    let error = store.load(&response_id).unwrap_err();

    let message = error.to_string();
    assert!(
        message.contains("failed to read stored web content"),
        "unexpected error: {message}"
    );
}

#[test]
fn available_selectors_lists_exact_keys() {
    let stored = StoredContent {
        kind: "web_search".into(),
        items: vec![
            StoredItem {
                url: Some("https://a.example".into()),
                query: Some("alpha".into()),
                title: None,
                content: "a".into(),
                metadata: json!({}),
            },
            StoredItem {
                url: Some("https://b.example".into()),
                query: Some("beta".into()),
                title: None,
                content: "b".into(),
                metadata: json!({}),
            },
        ],
    };

    let listing = available_selectors(&stored);
    assert!(listing.contains("urlIndex=0"));
    assert!(listing.contains("url=https://a.example"));
    assert!(listing.contains("queryIndex=0"));
    assert!(listing.contains("urlIndex=1"));
    assert!(listing.contains("queryIndex=1"));
    assert!(listing.contains("beta"));
}

#[test]
fn bind_session_changes_root() {
    let root = tempfile::tempdir().unwrap();
    let session_web = root.path().join("session-web");
    let store = WebAccessStore::new();
    store.bind_session(Some(session_web.clone()));
    assert_eq!(store.root(), session_web);
    store.bind_session(None);
    assert_ne!(store.root(), session_web);
}