@@ -4,95 +4,131 @@ mod prompt;
44use std:: env;
55
66pub use agent:: { Agent , run_agent} ;
7- use openai_api_rs:: v1:: { api:: OpenAIClient , common:: GPT3_5_TURBO } ;
7+ use openai_api_rs:: v1:: { api:: OpenAIClient , common} ;
88pub use prompt:: { PromptConfig , prompt_with_config} ;
99
1010use serde:: Deserialize ;
1111
12+ // OpenAI
13+ const OPENAI_API_ENDPOINT : & str = "https://api.openai.com/v1" ;
14+ const OPENAI_DEFAULT_MODEL : & str = common:: GPT4 ;
15+
1216// Deepseek
1317const DEEPSEEK_API_ENDPOINT : & str = "https://api.deepseek.com/v1" ;
14- const DEEPSEEK_V3 : & str = "deepseek-chat" ;
18+ const DEEPSEEK_DEFAULT_MODEL : & str = "deepseek-chat" ;
1519
1620// Anthropic
1721const ANTHROPIC_API_ENDPOINT : & str = "https://api.anthropic.com/v1" ;
18- const CLAUDE_3_5_SONNET : & str = "claude-3-5-sonnet-latest" ;
22+ const ANTHROPIC_DEFAULT_MODEL : & str = "claude-3-5-sonnet-latest" ;
1923
2024#[ derive( Debug , Clone , Deserialize ) ]
21- pub enum AiConfig {
22- #[ serde( rename = "openai" ) ]
23- OpenAI ( ModelConfig ) ,
24- #[ serde( rename = "anthropic" ) ]
25- Anthropic ( ModelConfig ) ,
26- #[ serde( rename = "deepseek" ) ]
27- DeepSeek ( ModelConfig ) ,
25+ pub struct AiConfig {
26+ pub openai : Option < ModelConfig > ,
27+ pub anthropic : Option < ModelConfig > ,
28+ pub deepseek : Option < ModelConfig > ,
29+ }
30+
31+ impl Default for AiConfig {
32+ fn default ( ) -> Self {
33+ Self {
34+ openai : env:: var ( "OPENAI_API_KEY" ) . ok ( ) . map ( |key| ModelConfig {
35+ api_key : key,
36+ api_endpoint : Some ( OPENAI_API_ENDPOINT . to_string ( ) ) ,
37+ model : Some ( OPENAI_DEFAULT_MODEL . to_string ( ) ) ,
38+ } ) ,
39+ anthropic : env:: var ( "CLAUDE_API_KEY" ) . ok ( ) . map ( |key| ModelConfig {
40+ api_key : key,
41+ api_endpoint : Some ( ANTHROPIC_API_ENDPOINT . to_string ( ) ) ,
42+ model : Some ( ANTHROPIC_DEFAULT_MODEL . to_string ( ) ) ,
43+ } ) ,
44+ deepseek : env:: var ( "DEEPKSEEK_API_KEY" ) . ok ( ) . map ( |key| ModelConfig {
45+ api_key : key,
46+ api_endpoint : Some ( DEEPSEEK_API_ENDPOINT . to_string ( ) ) ,
47+ model : Some ( DEEPSEEK_DEFAULT_MODEL . to_string ( ) ) ,
48+ } ) ,
49+ }
50+ }
2851}
2952
3053#[ derive( Debug , Clone , Deserialize ) ]
3154pub struct ModelConfig {
3255 pub api_key : String ,
56+ pub api_endpoint : Option < String > ,
3357 pub model : Option < String > ,
3458}
3559
36- impl AiConfig {
37- pub ( crate ) fn take_model ( & mut self ) -> Option < String > {
38- match self {
39- Self :: OpenAI ( ModelConfig { model, .. } ) => model. take ( ) ,
40- Self :: Anthropic ( ModelConfig { model, .. } ) => model. take ( ) ,
41- Self :: DeepSeek ( ModelConfig { model, .. } ) => model. take ( ) ,
60+ impl Default for ModelConfig {
61+ fn default ( ) -> Self {
62+ ModelConfig {
63+ #[ cfg( feature = "ai_test" ) ]
64+ api_key : "" . into ( ) ,
65+ #[ cfg( not( feature = "ai_test" ) ) ]
66+ api_key : env:: var ( "OPENAI_API_KEY" )
67+ . expect ( "Expect `OPENAI_API_KEY` environment variable." ) ,
68+ api_endpoint : Some ( OPENAI_API_ENDPOINT . to_string ( ) ) ,
69+ model : Some ( OPENAI_DEFAULT_MODEL . to_string ( ) ) ,
4270 }
4371 }
44-
45- pub ( crate ) fn set_model ( & mut self , m : String ) {
46- match self {
47- Self :: OpenAI ( ModelConfig { model, .. } ) => model. replace ( m) ,
48- Self :: Anthropic ( ModelConfig { model, .. } ) => model. replace ( m) ,
49- Self :: DeepSeek ( ModelConfig { model, .. } ) => model. replace ( m) ,
50- } ;
51- }
5272}
5373
54- #[ allow( unused) ]
55- pub ( crate ) fn openai_client ( config : Option < & AiConfig > ) -> OpenAIClient {
56- match config {
57- None => OpenAIClient :: builder ( )
58- . with_api_key ( env:: var ( "OPENAI_API_KEY" ) . expect ( "OPENAI_API_KEY not set" ) )
59- . build ( )
60- . unwrap ( ) ,
61- Some ( AiConfig :: OpenAI ( model_config) ) => {
62- let api_key = if model_config. api_key . is_empty ( ) {
63- env:: var ( "OPENAI_API_KEY" ) . expect ( "OPENAI_API_KEY not set" )
64- } else {
65- model_config. api_key . clone ( )
66- } ;
67- OpenAIClient :: builder ( )
68- . with_api_key ( api_key)
69- . build ( )
70- . unwrap ( )
74+ impl AiConfig {
75+ pub ( crate ) fn get_model_config (
76+ & self ,
77+ model_name : Option < String > ,
78+ ) -> Result < ModelConfig , String > {
79+ if let Some ( model) = model_name {
80+ match model {
81+ m if m. starts_with ( "gpt" ) => {
82+ if let Some ( openai) = self . openai . as_ref ( ) {
83+ let mut config = openai. clone ( ) ;
84+ config. model = Some ( m) ;
85+ Ok ( config)
86+ } else {
87+ Ok ( ModelConfig :: default ( ) )
88+ }
89+ }
90+ m if m. starts_with ( "claude" ) => {
91+ if let Some ( anthropic) = self . anthropic . as_ref ( ) {
92+ let mut config = anthropic. clone ( ) ;
93+ config. model = Some ( m) ;
94+ Ok ( config)
95+ } else {
96+ Ok ( ModelConfig {
97+ api_key : env:: var ( "CLAUDE_API_KEY" )
98+ . expect ( "Expect `CLAUDE_API_KEY` environment variable." ) ,
99+ api_endpoint : Some ( ANTHROPIC_API_ENDPOINT . to_string ( ) ) ,
100+ model : Some ( ANTHROPIC_DEFAULT_MODEL . to_string ( ) ) ,
101+ } )
102+ }
103+ }
104+ m if m. starts_with ( "deepseek" ) => {
105+ if let Some ( deepseek) = self . deepseek . as_ref ( ) {
106+ let mut config = deepseek. clone ( ) ;
107+ config. model = Some ( m) ;
108+ Ok ( config)
109+ } else {
110+ Ok ( ModelConfig {
111+ api_key : env:: var ( "DEEPSEEK_API_KEY" )
112+ . expect ( "Expect `DEEPSEEK_API_KEY` environment variable." ) ,
113+ api_endpoint : Some ( DEEPSEEK_API_ENDPOINT . to_string ( ) ) ,
114+ model : Some ( DEEPSEEK_DEFAULT_MODEL . to_string ( ) ) ,
115+ } )
116+ }
117+ }
118+ m => Err ( format ! ( "Unsupported model '{m}'." ) ) ,
119+ }
120+ } else {
121+ // Default is OpenAI model
122+ Ok ( ModelConfig :: default ( ) )
71123 }
72- Some ( AiConfig :: DeepSeek ( ModelConfig { api_key, .. } ) ) => OpenAIClient :: builder ( )
73- . with_endpoint ( DEEPSEEK_API_ENDPOINT )
74- . with_api_key ( api_key)
75- . build ( )
76- . unwrap ( ) ,
77- Some ( AiConfig :: Anthropic ( ModelConfig { api_key, .. } ) ) => OpenAIClient :: builder ( )
78- . with_endpoint ( ANTHROPIC_API_ENDPOINT )
79- . with_api_key ( api_key)
80- . build ( )
81- . unwrap ( ) ,
82124 }
83125}
84126
85- pub ( crate ) fn default_model ( config : Option < & AiConfig > ) -> String {
86- match config {
87- None => GPT3_5_TURBO . to_string ( ) ,
88- Some ( AiConfig :: OpenAI ( ModelConfig { model, .. } ) ) => {
89- model. clone ( ) . unwrap_or ( GPT3_5_TURBO . to_string ( ) )
90- }
91- Some ( AiConfig :: DeepSeek ( ModelConfig { model, .. } ) ) => {
92- model. clone ( ) . unwrap_or ( DEEPSEEK_V3 . to_string ( ) )
93- }
94- Some ( AiConfig :: Anthropic ( ModelConfig { model, .. } ) ) => {
95- model. clone ( ) . unwrap_or ( CLAUDE_3_5_SONNET . to_string ( ) )
96- }
97- }
127+ #[ allow( unused) ]
128+ pub ( crate ) fn openai_client ( config : & ModelConfig ) -> OpenAIClient {
129+ OpenAIClient :: builder ( )
130+ . with_api_key ( & config. api_key )
131+ . with_endpoint ( config. api_endpoint . as_ref ( ) . unwrap ( ) )
132+ . build ( )
133+ . unwrap ( )
98134}
0 commit comments