vv-agent 0.7.1

VectorVein agent runtime, SDK, CLI, tools, and workspace backends
Documentation
use super::super::token_usage::summarize_task_token_usage;
use crate::runtime::CancellationToken;
use crate::types::{
    last_assistant_output, AgentResult, AgentStatus, CompletionReason, CycleRecord, Message,
    Metadata,
};

pub(crate) fn execute_cycle_loop<F>(
    messages: Vec<Message>,
    shared_state: Metadata,
    cycle_executor: F,
    cancellation_token: Option<&CancellationToken>,
    max_cycles: u32,
) -> AgentResult
where
    F: FnMut(
        u32,
        &mut Vec<Message>,
        &mut Vec<CycleRecord>,
        &mut Metadata,
        Option<&CancellationToken>,
    ) -> Option<AgentResult>,
{
    execute_cycle_loop_with_state(
        messages,
        Vec::new(),
        shared_state,
        cycle_executor,
        cancellation_token,
        1,
        max_cycles,
    )
}

#[allow(clippy::too_many_arguments)]
pub(crate) fn execute_cycle_loop_with_state<F>(
    mut messages: Vec<Message>,
    mut cycles: Vec<CycleRecord>,
    mut shared_state: Metadata,
    mut cycle_executor: F,
    cancellation_token: Option<&CancellationToken>,
    cycle_index_start: u32,
    cycle_count: u32,
) -> AgentResult
where
    F: FnMut(
        u32,
        &mut Vec<Message>,
        &mut Vec<CycleRecord>,
        &mut Metadata,
        Option<&CancellationToken>,
    ) -> Option<AgentResult>,
{
    for offset in 0..cycle_count {
        let cycle_index = cycle_index_start.saturating_add(offset);
        if cancellation_token.is_some_and(CancellationToken::is_cancelled) {
            return cancelled_backend_result(messages, cycles, shared_state);
        }
        if let Some(result) = cycle_executor(
            cycle_index,
            &mut messages,
            &mut cycles,
            &mut shared_state,
            cancellation_token,
        ) {
            return result;
        }
    }

    let token_usage = summarize_task_token_usage(&cycles);
    let partial_output = last_assistant_output(&cycles);
    AgentResult {
        status: AgentStatus::MaxCycles,
        messages,
        cycles,
        completion_reason: Some(CompletionReason::MaxCycles),
        completion_tool_name: None,
        partial_output,
        budget_usage: None,
        budget_exhaustion: None,
        checkpoint_key: None,
        resume_observation: None,
        final_answer: Some("Reached max cycles without finish signal.".to_string()),
        wait_reason: None,
        error: None,
        shared_state,
        token_usage,
    }
}

pub(crate) fn cancelled_backend_result(
    messages: Vec<Message>,
    cycles: Vec<CycleRecord>,
    shared_state: Metadata,
) -> AgentResult {
    let token_usage = summarize_task_token_usage(&cycles);
    let partial_output = last_assistant_output(&cycles);
    AgentResult {
        status: AgentStatus::Failed,
        messages,
        cycles,
        completion_reason: Some(CompletionReason::Cancelled),
        completion_tool_name: None,
        partial_output,
        budget_usage: None,
        budget_exhaustion: None,
        checkpoint_key: None,
        resume_observation: None,
        final_answer: None,
        wait_reason: None,
        error: Some("Operation was cancelled".to_string()),
        shared_state,
        token_usage,
    }
}

pub(crate) fn failed_backend_result(
    messages: Vec<Message>,
    cycles: Vec<CycleRecord>,
    shared_state: Metadata,
    error: String,
) -> AgentResult {
    let token_usage = summarize_task_token_usage(&cycles);
    let partial_output = last_assistant_output(&cycles);
    AgentResult {
        status: AgentStatus::Failed,
        messages,
        cycles,
        completion_reason: Some(CompletionReason::Failed),
        completion_tool_name: None,
        partial_output,
        budget_usage: None,
        budget_exhaustion: None,
        checkpoint_key: None,
        resume_observation: None,
        final_answer: None,
        wait_reason: None,
        error: Some(error),
        shared_state,
        token_usage,
    }
}