vtcode-exec-events 0.98.5

Structured execution telemetry event schema used across VT Code crates.
Documentation
use std::error::Error;

use vtcode_exec_events::{
    CommandExecutionItem, CommandExecutionStatus, ItemCompletedEvent, ItemStartedEvent,
    ItemUpdatedEvent, ThreadEvent, ThreadItem, ThreadItemDetails, ThreadStartedEvent,
    TurnCompletedEvent, TurnStartedEvent, Usage,
};

fn main() -> Result<(), Box<dyn Error>> {
    let timeline = sample_timeline();

    println!("# execution timeline (JSONL)");
    for event in &timeline {
        let json = serde_json::to_string(event)?;
        println!("{json}");
    }

    println!("\n# completed commands");
    for event in &timeline {
        if let ThreadEvent::ItemCompleted(ItemCompletedEvent { item }) = event
            && let ThreadItemDetails::CommandExecution(command) = &item.details
        {
            println!(
                "{} => status={} exit_code={:?}",
                command.command,
                status_label(&command.status),
                command.exit_code
            );
        }
    }

    Ok(())
}

fn sample_timeline() -> Vec<ThreadEvent> {
    vec![
        ThreadEvent::ThreadStarted(ThreadStartedEvent {
            thread_id: "workspace.setup".into(),
        }),
        ThreadEvent::TurnStarted(TurnStartedEvent::default()),
        ThreadEvent::ItemStarted(ItemStartedEvent {
            item: ThreadItem {
                id: "command.git-init".into(),
                details: ThreadItemDetails::CommandExecution(Box::new(CommandExecutionItem {
                    command: "git init".into(),
                    arguments: None,
                    aggregated_output: String::new(),
                    exit_code: None,
                    status: CommandExecutionStatus::InProgress,
                })),
            },
        }),
        ThreadEvent::ItemUpdated(ItemUpdatedEvent {
            item: ThreadItem {
                id: "command.git-init".into(),
                details: ThreadItemDetails::CommandExecution(Box::new(CommandExecutionItem {
                    command: "git init".into(),
                    arguments: None,
                    aggregated_output: "Initialized empty Git repository".into(),
                    exit_code: None,
                    status: CommandExecutionStatus::InProgress,
                })),
            },
        }),
        ThreadEvent::ItemCompleted(ItemCompletedEvent {
            item: ThreadItem {
                id: "command.git-init".into(),
                details: ThreadItemDetails::CommandExecution(Box::new(CommandExecutionItem {
                    command: "git init".into(),
                    arguments: None,
                    aggregated_output: "Initialized empty Git repository".into(),
                    exit_code: Some(0),
                    status: CommandExecutionStatus::Completed,
                })),
            },
        }),
        ThreadEvent::TurnCompleted(TurnCompletedEvent {
            usage: Usage {
                input_tokens: 128,
                cached_input_tokens: 0,
                cache_creation_tokens: 0,
                output_tokens: 32,
            },
        }),
    ]
}

fn status_label(status: &CommandExecutionStatus) -> &'static str {
    match status {
        CommandExecutionStatus::Completed => "completed",
        CommandExecutionStatus::Failed => "failed",
        CommandExecutionStatus::InProgress => "in_progress",
    }
}