vtcode-core 0.175.6

Core library for VT Code - a Rust-based terminal coding agent
Documentation
use std::collections::HashMap;

use super::message::SessionMessage;
use crate::llm::provider::MessageRole;
use crate::utils::session_transcript_norm::{
    format_repeated_summary, normalize_recovery_line, normalized_transcript_key, push_clean_transcript_line,
    should_drop_transcript_line, summarize_tool_block,
};

pub(crate) fn progress_transcript_from_recent_messages(recent_messages: &[SessionMessage]) -> Vec<String> {
    let mut transcript = Vec::with_capacity(recent_messages.len());

    for message in recent_messages {
        if !matches!(message.role, MessageRole::User | MessageRole::Assistant) {
            continue;
        }

        let content = message.content.trim();
        let content: &str = content.as_ref();
        if !content.is_empty() && transcript.last().is_none_or(|last: &String| last.as_str() != content) {
            transcript.push(content.to_string());
        }
    }

    clean_transcript_lines(&transcript)
}

pub(crate) fn clean_transcript_lines(lines: &[String]) -> Vec<String> {
    let mut cleaned = Vec::new();
    let mut seen_tool_blocks: HashMap<String, (usize, usize, String)> = HashMap::new();
    let mut index = 0usize;

    while index < lines.len() {
        let line = lines[index].trim_end();

        if should_reset_tool_dedupe_scope(line) {
            seen_tool_blocks.clear();
        }

        if let Some(replacement) = normalize_recovery_line(line) {
            push_clean_transcript_line(&mut cleaned, replacement);
            index += 1;
            continue;
        }

        if should_drop_transcript_line(line) {
            index += 1;
            continue;
        }

        if line.trim_start().starts_with("• ") {
            let (summary, next_index) = summarize_tool_block(lines, index);
            let signature = normalized_transcript_key(&summary);

            if let Some((first_index, repeats, original_line)) = seen_tool_blocks.get_mut(&signature) {
                *repeats += 1;
                if let Some(existing) = cleaned.get_mut(*first_index) {
                    *existing = format_repeated_summary(original_line, *repeats);
                }
            } else {
                let insertion_index = cleaned.len();
                push_clean_transcript_line(&mut cleaned, summary);
                if cleaned.len() > insertion_index {
                    seen_tool_blocks.insert(signature, (insertion_index, 1, cleaned[insertion_index].clone()));
                }
            }
            index = next_index;
            continue;
        }

        push_clean_transcript_line(&mut cleaned, line.to_string());
        index += 1;
    }

    while cleaned.last().is_some_and(|line: &String| line.is_empty()) {
        cleaned.pop();
    }

    cleaned
}

fn should_reset_tool_dedupe_scope(line: &str) -> bool {
    let trimmed = line.trim();
    !trimmed.is_empty() && !line.starts_with(' ') && !trimmed.starts_with("• ") && !trimmed.starts_with("[!]")
}