vv-agent 0.8.0

VectorVein agent runtime, SDK, CLI, tools, and workspace backends
Documentation
use std::collections::BTreeMap;
use std::sync::Arc;

use serde_json::Value;

use crate::llm::{LlmRequest, LlmStreamCallback};
use crate::runtime::RunEventHandler;
use crate::types::{AgentTask, Message};

use super::RuntimeRunControls;

pub(super) fn build_model_request(
    task: &AgentTask,
    controls: &RuntimeRunControls,
    messages: &[Message],
    tool_schemas: &[Value],
) -> LlmRequest {
    let mut request = LlmRequest::new(task.model.clone(), messages.to_vec());
    request.tools = tool_schemas.to_vec();
    let mut request_metadata = task.metadata.clone();
    if let Some(execution_context) = controls.execution_context.as_ref() {
        request_metadata.extend(execution_context.metadata.clone());
    }
    request.metadata = Value::Object(request_metadata.into_iter().collect());
    request.model_settings = task.model_settings.clone();
    request
}

pub(super) fn effective_model_call_target(
    task: &AgentTask,
    controls: &RuntimeRunControls,
    default_backend: Option<&str>,
) -> (String, String) {
    let metadata = controls
        .execution_context
        .as_ref()
        .map(|context| &context.metadata);
    let backend = metadata
        .and_then(|metadata| identity(metadata, &["_vv_agent_resolved_backend"]))
        .or_else(|| default_backend.map(str::to_string))
        .unwrap_or_else(|| "direct".to_string());
    let model = metadata
        .and_then(|metadata| identity(metadata, &["_vv_agent_resolved_model"]))
        .unwrap_or_else(|| task.model.clone());
    (backend, model)
}

pub(super) fn cycle_stream_callback(
    handler: Option<&RunEventHandler>,
    metadata: &BTreeMap<String, Value>,
    cycle_index: u32,
) -> Option<LlmStreamCallback> {
    handler.map(|handler| {
        let handler = handler.clone();
        let run_id = identity(metadata, &["_vv_agent_run_id", "run_id"])
            .unwrap_or_else(|| "runtime".to_string());
        let trace_id = identity(metadata, &["_vv_agent_trace_id", "trace_id"])
            .unwrap_or_else(|| run_id.clone());
        let agent_name = identity(metadata, &["_vv_agent_agent_name", "agent_name"])
            .unwrap_or_else(|| "runtime".to_string());
        let session_id = identity(metadata, &["_vv_agent_session_id", "session_id"]);
        let parent_run_id = identity(metadata, &["_vv_agent_parent_run_id", "parent_run_id"]);
        let input = identity(metadata, &["_vv_agent_input"]).unwrap_or_default();
        let context = crate::runner::RuntimeEventContext::new(
            run_id, trace_id, agent_name, session_id, input,
        );
        Arc::new(move |event: &BTreeMap<String, Value>| {
            let mut event = event.clone();
            event.insert("cycle".to_string(), Value::from(cycle_index));
            if let Some(mut event) = crate::runner::map_stream_event(&event, &context) {
                if let Some(parent_run_id) = parent_run_id.as_ref() {
                    event = event.with_parent_run_id(parent_run_id);
                }
                handler(&event);
            }
        }) as LlmStreamCallback
    })
}

fn identity(metadata: &BTreeMap<String, Value>, keys: &[&str]) -> Option<String> {
    keys.iter().find_map(|key| {
        metadata
            .get(*key)
            .and_then(Value::as_str)
            .map(str::trim)
            .filter(|value| !value.is_empty())
            .map(str::to_string)
    })
}