...
This commit is contained in:
		
							
								
								
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -63,4 +63,7 @@ sidebars.ts | ||||
|  | ||||
| tsconfig.json | ||||
| Cargo.toml.bak | ||||
| for_augment | ||||
| for_augment | ||||
|  | ||||
| myenv.sh | ||||
|  | ||||
|   | ||||
| @@ -27,6 +27,7 @@ members = [ | ||||
|     "rhai", | ||||
|     "herodo", | ||||
|     "packages/clients/hetznerclient", | ||||
|     "packages/ai/codemonkey", | ||||
| ] | ||||
| resolver = "2" | ||||
|  | ||||
|   | ||||
							
								
								
									
										14
									
								
								config/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								config/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| # Environment Configuration | ||||
|  | ||||
| To set up your environment variables: | ||||
|  | ||||
| 1. Copy the template file to `env.sh`: | ||||
|  | ||||
|     ```bash | ||||
|     cp config/myenv_templ.sh config/env.sh | ||||
|     ``` | ||||
|  | ||||
| 2. Edit `config/env.sh` and fill in your specific values for the variables. | ||||
|  | ||||
| 3. This file (`config/env.sh`) is excluded from version control by the project's `.gitignore` configuration, ensuring your sensitive information remains local and is never committed to the repository. | ||||
|  | ||||
							
								
								
									
										6
									
								
								config/myenv_templ.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								config/myenv_templ.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
|  | ||||
|  | ||||
| export OPENROUTER_API_KEY="" | ||||
| export GROQ_API_KEY="" | ||||
| export CEREBRAS_API_KEY="" | ||||
| export OPENAI_API_KEY="sk-xxxxxxx" | ||||
							
								
								
									
										15
									
								
								examples_rust/ai/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								examples_rust/ai/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| [package] | ||||
| name = "openrouter_example" | ||||
| version = "0.1.0" | ||||
| edition = "2021" | ||||
|  | ||||
| [workspace] | ||||
|  | ||||
| [[bin]] | ||||
| name = "openrouter_example" | ||||
| path = "openrouter_example.rs" | ||||
|  | ||||
| [dependencies] | ||||
| codemonkey = { path = "../../packages/ai/codemonkey" } | ||||
| openai-api-rs = "6.0.8" | ||||
| tokio = { version = "1.0", features = ["full"] } | ||||
							
								
								
									
										47
									
								
								examples_rust/ai/openrouter_example.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								examples_rust/ai/openrouter_example.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| use codemonkey::{create_ai_provider, AIProviderType, CompletionRequestBuilder, Message, MessageRole, Content}; | ||||
| use std::error::Error; | ||||
|  | ||||
| #[tokio::main] | ||||
| async fn main() -> Result<(), Box<dyn Error>> { | ||||
|  | ||||
|     let (mut provider, provider_type) = create_ai_provider(AIProviderType::OpenRouter)?; | ||||
|  | ||||
|     let messages = vec![Message { | ||||
|         role: MessageRole::user, | ||||
|         content: Content::Text("Explain the concept of a factory design pattern in Rust.".to_string()), | ||||
|         name: None, | ||||
|         tool_calls: None, | ||||
|         tool_call_id: None, | ||||
|     }]; | ||||
|  | ||||
|     println!("Sending request to OpenRouter..."); | ||||
|     let response = CompletionRequestBuilder::new( | ||||
|         &mut *provider, | ||||
|         "openai/gpt-oss-120b".to_string(), // Model name as specified by the user | ||||
|         messages, | ||||
|         provider_type, // Pass the provider_type | ||||
|     ) | ||||
|     .temperature(1.0) | ||||
|     .max_tokens(8192) | ||||
|     .top_p(1.0) | ||||
|     .reasoning_effort("medium") | ||||
|     .stream(false) | ||||
|     .openrouter_options(|builder| { | ||||
|         builder.provider( | ||||
|             codemonkey::OpenRouterProviderOptionsBuilder::new() | ||||
|                 .order(vec!["cerebras"]) | ||||
|                 .build(), | ||||
|         ) | ||||
|     }) | ||||
|     .completion() | ||||
|     .await?; | ||||
|  | ||||
|     for choice in response.choices { | ||||
|         if let Some(content) = choice.message.content { | ||||
|             print!("{}", content); | ||||
|         } | ||||
|     } | ||||
|     println!(); | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
							
								
								
									
										13
									
								
								examples_rust/ai/run.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										13
									
								
								examples_rust/ai/run.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| #!/bin/bash | ||||
| set -e | ||||
|  | ||||
| # Change to directory where this script is located | ||||
| cd "$(dirname "${BASH_SOURCE[0]}")" | ||||
|  | ||||
| source ../../config/myenv.sh | ||||
|  | ||||
| # Build the example | ||||
| cargo build | ||||
|  | ||||
| # Run the example | ||||
| cargo run --bin openrouter_example | ||||
							
								
								
									
										10
									
								
								packages/ai/codemonkey/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								packages/ai/codemonkey/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| [package] | ||||
| name = "codemonkey" | ||||
| version = "0.1.0" | ||||
| edition = "2021" | ||||
|  | ||||
| [dependencies] | ||||
| tokio = { version = "1", features = ["full"] } | ||||
| async-trait = "0.1.80" | ||||
| openrouter-rs = "0.4.5" | ||||
| serde = { version = "1.0", features = ["derive"] } | ||||
							
								
								
									
										227
									
								
								packages/ai/codemonkey/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								packages/ai/codemonkey/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,227 @@ | ||||
| use async_trait::async_trait; | ||||
| use openrouter_rs::{OpenRouterClient, api::chat::*, types::Role, ChatCompletionResponse}; // Added ChatCompletionResponse here | ||||
| use std::env; | ||||
| use std::error::Error; | ||||
|  | ||||
| // Re-export Message and MessageRole for easier use in client code | ||||
| pub use openrouter_rs::api::chat::Message; | ||||
| pub use openrouter_rs::types::Role as MessageRole; | ||||
| // Removed the problematic import for ChatCompletionResponse | ||||
| // pub use openrouter_rs::api::chat::chat_completion::ChatCompletionResponse;  | ||||
|  | ||||
| #[async_trait] | ||||
| pub trait AIProvider { | ||||
|     async fn completion( | ||||
|         &mut self, | ||||
|         request: CompletionRequest, | ||||
|     ) -> Result<ChatCompletionResponse, Box<dyn Error>>; | ||||
| } | ||||
|  | ||||
| pub struct CompletionRequest { | ||||
|     pub model: String, | ||||
|     pub messages: Vec<Message>, | ||||
|     pub temperature: Option<f64>, | ||||
|     pub max_tokens: Option<i64>, | ||||
|     pub top_p: Option<f64>, | ||||
|     pub stream: Option<bool>, | ||||
|     pub stop: Option<Vec<String>>, | ||||
| } | ||||
|  | ||||
| pub struct CompletionRequestBuilder<'a> { | ||||
|     provider: &'a mut dyn AIProvider, | ||||
|     model: String, | ||||
|     messages: Vec<Message>, | ||||
|     temperature: Option<f64>, | ||||
|     max_tokens: Option<i64>, | ||||
|     top_p: Option<f64>, | ||||
|     stream: Option<bool>, | ||||
|     stop: Option<Vec<String>>, | ||||
|     provider_type: AIProviderType, | ||||
| } | ||||
|  | ||||
| impl<'a> CompletionRequestBuilder<'a> { | ||||
|     pub fn new(provider: &'a mut dyn AIProvider, model: String, messages: Vec<Message>, provider_type: AIProviderType) -> Self { | ||||
|         Self { | ||||
|             provider, | ||||
|             model, | ||||
|             messages, | ||||
|             temperature: None, | ||||
|             max_tokens: None, | ||||
|             top_p: None, | ||||
|             stream: None, | ||||
|             stop: None, | ||||
|             provider_type, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn temperature(mut self, temperature: f64) -> Self { | ||||
|         self.temperature = Some(temperature); | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     pub fn max_tokens(mut self, max_tokens: i64) -> Self { | ||||
|         self.max_tokens = Some(max_tokens); | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     pub fn top_p(mut self, top_p: f64) -> Self { | ||||
|         self.top_p = Some(top_p); | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     pub fn stream(mut self, stream: bool) -> Self { | ||||
|         self.stream = Some(stream); | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     pub fn stop(mut self, stop: Vec<String>) -> Self { | ||||
|         self.stop = Some(stop); | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     pub async fn completion(self) -> Result<ChatCompletionResponse, Box<dyn Error>> { | ||||
|         let request = CompletionRequest { | ||||
|             model: self.model, | ||||
|             messages: self.messages, | ||||
|             temperature: self.temperature, | ||||
|             max_tokens: self.max_tokens, | ||||
|             top_p: self.top_p, | ||||
|             stream: self.stream, | ||||
|             stop: self.stop, | ||||
|         }; | ||||
|         self.provider.completion(request).await | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub struct GroqAIProvider { | ||||
|     client: OpenRouterClient, | ||||
| } | ||||
|  | ||||
| #[async_trait] | ||||
| impl AIProvider for GroqAIProvider { | ||||
|     async fn completion( | ||||
|         &mut self, | ||||
|         request: CompletionRequest, | ||||
|     ) -> Result<ChatCompletionResponse, Box<dyn Error>> { | ||||
|         let chat_request = ChatCompletionRequest::builder() | ||||
|             .model(request.model) | ||||
|             .messages(request.messages) | ||||
|             .temperature(request.temperature.unwrap_or(1.0)) | ||||
|             .max_tokens(request.max_tokens.map(|x| x as u32).unwrap_or(2048)) | ||||
|             .top_p(request.top_p.unwrap_or(1.0)) | ||||
|             .stream(request.stream.unwrap_or(false)) // Corrected to field assignment | ||||
|             .stop(request.stop.unwrap_or_default()) | ||||
|             .build()?; | ||||
|  | ||||
|         let result = self.client.send_chat_completion(&chat_request).await?; | ||||
|         Ok(result) | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub struct OpenAIProvider { | ||||
|     client: OpenRouterClient, | ||||
| } | ||||
|  | ||||
| #[async_trait] | ||||
| impl AIProvider for OpenAIProvider { | ||||
|     async fn completion( | ||||
|         &mut self, | ||||
|         request: CompletionRequest, | ||||
|     ) -> Result<ChatCompletionResponse, Box<dyn Error>> { | ||||
|         let chat_request = ChatCompletionRequest::builder() | ||||
|             .model(request.model) | ||||
|             .messages(request.messages) | ||||
|             .temperature(request.temperature.unwrap_or(1.0)) | ||||
|             .max_tokens(request.max_tokens.map(|x| x as u32).unwrap_or(2048)) | ||||
|             .top_p(request.top_p.unwrap_or(1.0)) | ||||
|             .stream(request.stream.unwrap_or(false)) // Corrected to field assignment | ||||
|             .stop(request.stop.unwrap_or_default()) | ||||
|             .build()?; | ||||
|  | ||||
|         let result = self.client.send_chat_completion(&chat_request).await?; | ||||
|         Ok(result) | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub struct OpenRouterAIProvider { | ||||
|     client: OpenRouterClient, | ||||
| } | ||||
|  | ||||
| #[async_trait] | ||||
| impl AIProvider for OpenRouterAIProvider { | ||||
|     async fn completion( | ||||
|         &mut self, | ||||
|         request: CompletionRequest, | ||||
|     ) -> Result<ChatCompletionResponse, Box<dyn Error>> { | ||||
|         let chat_request = ChatCompletionRequest::builder() | ||||
|             .model(request.model) | ||||
|             .messages(request.messages) | ||||
|             .temperature(request.temperature.unwrap_or(1.0)) | ||||
|             .max_tokens(request.max_tokens.map(|x| x as u32).unwrap_or(2048)) | ||||
|             .top_p(request.top_p.unwrap_or(1.0)) | ||||
|             .stream(request.stream.unwrap_or(false)) // Corrected to field assignment | ||||
|             .stop(request.stop.unwrap_or_default()) | ||||
|             .build()?; | ||||
|  | ||||
|         let result = self.client.send_chat_completion(&chat_request).await?; | ||||
|         Ok(result) | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub struct CerebrasAIProvider { | ||||
|     client: OpenRouterClient, | ||||
| } | ||||
|  | ||||
| #[async_trait] | ||||
| impl AIProvider for CerebrasAIProvider { | ||||
|     async fn completion( | ||||
|         &mut self, | ||||
|         request: CompletionRequest, | ||||
|     ) -> Result<ChatCompletionResponse, Box<dyn Error>> { | ||||
|         let chat_request = ChatCompletionRequest::builder() | ||||
|             .model(request.model) | ||||
|             .messages(request.messages) | ||||
|             .temperature(request.temperature.unwrap_or(1.0)) | ||||
|             .max_tokens(request.max_tokens.map(|x| x as u32).unwrap_or(2048)) | ||||
|             .top_p(request.top_p.unwrap_or(1.0)) | ||||
|             .stream(request.stream.unwrap_or(false)) // Corrected to field assignment | ||||
|             .stop(request.stop.unwrap_or_default()) | ||||
|             .build()?; | ||||
|  | ||||
|         let result = self.client.send_chat_completion(&chat_request).await?; | ||||
|         Ok(result) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(PartialEq)] | ||||
| pub enum AIProviderType { | ||||
|     Groq, | ||||
|     OpenAI, | ||||
|     OpenRouter, | ||||
|     Cerebras, | ||||
| } | ||||
|  | ||||
| pub fn create_ai_provider(provider_type: AIProviderType) -> Result<(Box<dyn AIProvider>, AIProviderType), Box<dyn Error>> { | ||||
|     match provider_type { | ||||
|         AIProviderType::Groq => { | ||||
|             let api_key = env::var("GROQ_API_KEY")?; | ||||
|             let client = OpenRouterClient::builder().api_key(api_key).build()?; | ||||
|             Ok((Box::new(GroqAIProvider { client }), AIProviderType::Groq)) | ||||
|         } | ||||
|         AIProviderType::OpenAI => { | ||||
|             let api_key = env::var("OPENAI_API_KEY")?; | ||||
|             let client = OpenRouterClient::builder().api_key(api_key).build()?; | ||||
|             Ok((Box::new(OpenAIProvider { client }), AIProviderType::OpenAI)) | ||||
|         } | ||||
|         AIProviderType::OpenRouter => { | ||||
|             let api_key = env::var("OPENROUTER_API_KEY")?; | ||||
|             let client = OpenRouterClient::builder().api_key(api_key).build()?; | ||||
|             Ok((Box::new(OpenRouterAIProvider { client }), AIProviderType::OpenRouter)) | ||||
|         } | ||||
|         AIProviderType::Cerebras => { | ||||
|             let api_key = env::var("CEREBRAS_API_KEY")?; | ||||
|             let client = OpenRouterClient::builder().api_key(api_key).build()?; | ||||
|             Ok((Box::new(CerebrasAIProvider { client }), AIProviderType::Cerebras)) | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user