Skip to main content

vv_agent/app_server/
host.rs

1use std::path::PathBuf;
2
3use serde_json::json;
4use thiserror::Error;
5
6use crate::app_server::protocol::{AppModelInfo, ModelListParams, ModelListResponse};
7use crate::types::Metadata;
8use crate::{Agent, RunConfig};
9
10#[derive(Debug, Clone, PartialEq)]
11pub struct AgentResolutionRequest {
12    pub thread_id: String,
13    pub agent_key: String,
14    pub cwd: Option<PathBuf>,
15    pub metadata: Metadata,
16}
17
18#[derive(Debug, Clone, PartialEq)]
19pub struct RunConfigResolutionRequest {
20    pub thread_id: String,
21    pub agent_key: String,
22    pub cwd: Option<PathBuf>,
23    pub metadata: Metadata,
24}
25
26#[derive(Debug, Clone, PartialEq, Eq, Error)]
27#[error("{message}")]
28pub struct AppServerHostError {
29    message: String,
30}
31
32impl AppServerHostError {
33    pub fn new(message: impl Into<String>) -> Self {
34        Self {
35            message: message.into(),
36        }
37    }
38
39    pub fn message(&self) -> &str {
40        &self.message
41    }
42}
43
44impl From<String> for AppServerHostError {
45    fn from(message: String) -> Self {
46        Self::new(message)
47    }
48}
49
50impl From<&str> for AppServerHostError {
51    fn from(message: &str) -> Self {
52        Self::new(message)
53    }
54}
55
56pub trait AppServerHost: Send + Sync {
57    fn resolve_agent(&self, request: &AgentResolutionRequest) -> Result<Agent, AppServerHostError>;
58
59    fn build_run_config(
60        &self,
61        request: &RunConfigResolutionRequest,
62    ) -> Result<RunConfig, AppServerHostError>;
63
64    fn list_models(
65        &self,
66        request: &ModelListParams,
67    ) -> Result<ModelListResponse, AppServerHostError>;
68}
69
70#[derive(Clone, Default)]
71pub struct DefaultAppServerHost {
72    agent: Option<Agent>,
73    run_config: Option<RunConfig>,
74    models: Vec<AppModelInfo>,
75}
76
77impl DefaultAppServerHost {
78    pub fn new() -> Self {
79        Self::default()
80    }
81
82    pub fn from_agent(agent: Agent) -> Self {
83        Self::new().with_agent(agent)
84    }
85
86    pub fn with_agent(mut self, agent: Agent) -> Self {
87        self.agent = Some(agent);
88        self
89    }
90
91    pub fn with_run_config(mut self, run_config: RunConfig) -> Self {
92        self.run_config = Some(run_config);
93        self
94    }
95
96    pub fn with_models(mut self, models: Vec<AppModelInfo>) -> Self {
97        self.models = models;
98        self
99    }
100}
101
102impl AppServerHost for DefaultAppServerHost {
103    fn resolve_agent(&self, request: &AgentResolutionRequest) -> Result<Agent, AppServerHostError> {
104        if let Some(agent) = &self.agent {
105            return Ok(agent.clone());
106        }
107        let name = if request.agent_key.trim().is_empty() {
108            "assistant"
109        } else {
110            request.agent_key.as_str()
111        };
112        Agent::builder(name)
113            .instructions("You are the default vv-agent App Server assistant.")
114            .build()
115            .map_err(AppServerHostError::new)
116    }
117
118    fn build_run_config(
119        &self,
120        request: &RunConfigResolutionRequest,
121    ) -> Result<RunConfig, AppServerHostError> {
122        if let Some(run_config) = &self.run_config {
123            return Ok(run_config.clone());
124        }
125        let mut run_config = RunConfig {
126            workspace: request.cwd.clone(),
127            ..RunConfig::default()
128        };
129        run_config
130            .metadata
131            .insert("agent_key".to_string(), json!(request.agent_key));
132        Ok(run_config)
133    }
134
135    fn list_models(
136        &self,
137        _request: &ModelListParams,
138    ) -> Result<ModelListResponse, AppServerHostError> {
139        Ok(ModelListResponse {
140            models: self.models.clone(),
141        })
142    }
143}