vv-agent 0.6.2

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

use crate::runtime::sub_task_manager::SubTaskManager;
use crate::tools::base::{SubTaskRunner, ToolContext};
use crate::tools::common::tool_error_with_code;
use crate::types::{SubTaskRequest, ToolExecutionResult};

use super::request::BatchRequestEntry;
use super::response;

pub(super) fn start_single_async(
    context: &mut ToolContext,
    runner: SubTaskRunner,
    mut request: SubTaskRequest,
) -> ToolExecutionResult {
    let Some(manager) = context.sub_task_manager.clone() else {
        return tool_error_with_code(
            "Sub-task manager is not available for async mode",
            "sub_task_manager_unavailable",
        );
    };

    let (task_id, session_id) =
        SubTaskManager::next_task_identity(&context.task_id, &request.agent_name);
    request
        .metadata
        .insert("task_id".to_string(), Value::String(task_id.clone()));
    request
        .metadata
        .insert("session_id".to_string(), Value::String(session_id.clone()));
    let agent_name = request.agent_name.clone();
    let task_description = request.task_description.clone();
    if let Err(error) = manager.submit_with_workspace(
        task_id.clone(),
        session_id.clone(),
        agent_name.clone(),
        task_description.clone(),
        Some(context.workspace_backend.clone()),
        move || runner(request),
    ) {
        return tool_error_with_code(error, "sub_task_already_running");
    }

    response::success(json!({
        "task_id": task_id,
        "session_id": session_id,
        "agent_name": agent_name,
        "status": "running",
        "task_description": task_description,
        "wait_for_completion": false,
    }))
}

pub(super) fn start_batch_async(
    context: &mut ToolContext,
    runner: SubTaskRunner,
    agent_name: &str,
    total: usize,
    entries: Vec<BatchRequestEntry>,
) -> ToolExecutionResult {
    let Some(manager) = context.sub_task_manager.clone() else {
        return tool_error_with_code(
            "Sub-task manager is not available for async mode",
            "sub_task_manager_unavailable",
        );
    };

    let mut results = Vec::new();
    let mut task_ids = Vec::new();
    let mut started = 0usize;
    let mut failed = 0usize;
    for entry in entries {
        let Some(mut request) = entry.request else {
            failed += 1;
            results.push(json!({
                "index": entry.index,
                "status": "failed",
                "error": entry.error.unwrap_or_else(|| "Invalid task item".to_string()),
            }));
            continue;
        };
        let (task_id, session_id) =
            SubTaskManager::next_task_identity(&context.task_id, agent_name);
        request
            .metadata
            .insert("task_id".to_string(), Value::String(task_id.clone()));
        request
            .metadata
            .insert("session_id".to_string(), Value::String(session_id.clone()));
        let task_title = request.task_description.clone();
        let runner = runner.clone();
        if let Err(error) = manager.submit_with_workspace(
            task_id.clone(),
            session_id.clone(),
            agent_name.to_string(),
            task_title.clone(),
            Some(context.workspace_backend.clone()),
            move || runner(request),
        ) {
            results.push(json!({
                "index": entry.index,
                "task_id": task_id,
                "session_id": session_id,
                "agent_name": agent_name,
                "status": "failed",
                "error": error,
            }));
            continue;
        }
        started += 1;
        task_ids.push(task_id.clone());
        results.push(json!({
            "index": entry.index,
            "task_id": task_id,
            "session_id": session_id,
            "agent_name": agent_name,
            "status": "running",
            "task_description": task_title,
        }));
    }

    response::success(json!({
        "summary": {
            "total": total,
            "accepted": started,
            "failed": failed,
        },
        "task_ids": task_ids,
        "results": results,
        "wait_for_completion": false,
    }))
}