vv-agent 0.6.2

VectorVein agent runtime, SDK, CLI, tools, and workspace backends
Documentation
use serde_json::Value;

pub(super) fn collect_raw_content(blocks: &mut Vec<Value>, chunk: Value) {
    match chunk {
        Value::Array(items) => {
            for item in items {
                collect_raw_content(blocks, item);
            }
        }
        Value::Object(object) => collect_raw_content_object(blocks, object),
        _ => {}
    }
}

fn collect_raw_content_object(blocks: &mut Vec<Value>, object: serde_json::Map<String, Value>) {
    let chunk_type = object
        .get("type")
        .and_then(Value::as_str)
        .unwrap_or_default();
    match chunk_type {
        "thinking_delta" => {
            let index = find_or_create_raw_block(
                blocks,
                "thinking",
                &[("thinking", ""), ("signature", "")],
            );
            append_raw_block_string(blocks, index, "thinking", object.get("thinking"));
        }
        "signature_delta" => {
            let index = find_or_create_raw_block(
                blocks,
                "thinking",
                &[("thinking", ""), ("signature", "")],
            );
            append_raw_block_string(blocks, index, "signature", object.get("signature"));
        }
        "text_delta" => {
            let index = find_or_create_raw_block(blocks, "text", &[("text", "")]);
            append_raw_block_string(blocks, index, "text", object.get("text"));
        }
        "input_json_delta" => {}
        "thinking" | "text" | "tool_use" => {
            if !raw_block_exists(blocks, &object) {
                blocks.push(Value::Object(object));
            }
        }
        _ => blocks.push(Value::Object(object)),
    }
}

fn find_or_create_raw_block(
    blocks: &mut Vec<Value>,
    block_type: &str,
    defaults: &[(&str, &str)],
) -> usize {
    if let Some(index) = blocks.iter().position(|block| {
        block
            .get("type")
            .and_then(Value::as_str)
            .is_some_and(|candidate| candidate == block_type)
    }) {
        return index;
    }

    let mut block = serde_json::Map::new();
    block.insert("type".to_string(), Value::String(block_type.to_string()));
    for (key, value) in defaults {
        block.insert((*key).to_string(), Value::String((*value).to_string()));
    }
    blocks.push(Value::Object(block));
    blocks.len() - 1
}

fn append_raw_block_string(
    blocks: &mut [Value],
    index: usize,
    key: &str,
    addition: Option<&Value>,
) {
    let addition = addition.and_then(Value::as_str).unwrap_or_default();
    let Some(block) = blocks.get_mut(index).and_then(Value::as_object_mut) else {
        return;
    };
    let mut value = block
        .get(key)
        .and_then(Value::as_str)
        .unwrap_or_default()
        .to_string();
    value.push_str(addition);
    block.insert(key.to_string(), Value::String(value));
}

fn raw_block_exists(blocks: &[Value], candidate: &serde_json::Map<String, Value>) -> bool {
    let candidate_type = candidate.get("type");
    let candidate_id = candidate.get("id");
    blocks.iter().any(|block| {
        let Some(block) = block.as_object() else {
            return false;
        };
        if block.get("type") != candidate_type {
            return false;
        }
        if let Some(candidate_id) = candidate_id {
            return block.get("id") == Some(candidate_id);
        }
        block == candidate
    })
}