vv_agent/app_server/
host.rs1use 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}