-
Notifications
You must be signed in to change notification settings - Fork 5.8k
feat: added groq provider #494
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
3b8ce1d
eef6f3c
4715cb9
07147eb
0a91706
ab705fd
8ce3bdd
4a51019
726471d
38ecbdc
d9d184d
c025802
e3485bf
152ea97
aa6b678
d66e48a
13d8967
5cd0c06
ab5279e
7f4a90f
529f5d1
2b2dad7
0674f30
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,13 @@ | ||
| use crate::error::{to_env_var, ConfigError}; | ||
| use config::{Config, Environment}; | ||
| use goose::providers::configs::GoogleProviderConfig; | ||
| use goose::providers::configs::{GoogleProviderConfig, GroqProviderConfig}; | ||
| use goose::providers::{ | ||
| configs::{ | ||
| DatabricksAuth, DatabricksProviderConfig, ModelConfig, OllamaProviderConfig, | ||
| OpenAiProviderConfig, ProviderConfig, | ||
| }, | ||
| factory::ProviderType, | ||
| google, ollama, | ||
| google, groq, ollama, | ||
| utils::ImageFormat, | ||
| }; | ||
| use serde::Deserialize; | ||
|
|
@@ -88,6 +88,17 @@ pub enum ProviderSettings { | |
| #[serde(default)] | ||
| max_tokens: Option<i32>, | ||
| }, | ||
| Groq { | ||
| #[serde(default = "default_groq_host")] | ||
| host: String, | ||
| api_key: String, | ||
| #[serde(default = "default_groq_model")] | ||
| model: String, | ||
| #[serde(default)] | ||
| temperature: Option<f32>, | ||
| #[serde(default)] | ||
| max_tokens: Option<i32>, | ||
| }, | ||
| } | ||
|
|
||
| impl ProviderSettings { | ||
|
|
@@ -99,6 +110,7 @@ impl ProviderSettings { | |
| ProviderSettings::Databricks { .. } => ProviderType::Databricks, | ||
| ProviderSettings::Ollama { .. } => ProviderType::Ollama, | ||
| ProviderSettings::Google { .. } => ProviderType::Google, | ||
| ProviderSettings::Groq { .. } => ProviderType::Groq, | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -168,6 +180,19 @@ impl ProviderSettings { | |
| .with_temperature(temperature) | ||
| .with_max_tokens(max_tokens), | ||
| }), | ||
| ProviderSettings::Groq { | ||
| host, | ||
| api_key, | ||
| model, | ||
| temperature, | ||
| max_tokens, | ||
| } => ProviderConfig::Groq(GroqProviderConfig { | ||
| host, | ||
| api_key, | ||
| model: ModelConfig::new(model) | ||
| .with_temperature(temperature) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. context_limit and estimate_factor should go here as well for Groq and Google |
||
| .with_max_tokens(max_tokens), | ||
| }), | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -267,6 +292,14 @@ fn default_google_model() -> String { | |
| google::GOOGLE_DEFAULT_MODEL.to_string() | ||
| } | ||
|
|
||
| fn default_groq_host() -> String { | ||
| groq::GROQ_API_HOST.to_string() | ||
| } | ||
|
|
||
| fn default_groq_model() -> String { | ||
| groq::GROQ_DEFAULT_MODEL.to_string() | ||
| } | ||
|
|
||
| fn default_image_format() -> ImageFormat { | ||
| ImageFormat::Anthropic | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,11 +8,12 @@ use super::base::{Provider, ProviderUsage, Usage}; | |
| use super::configs::{DatabricksAuth, DatabricksProviderConfig, ModelConfig, ProviderModelConfig}; | ||
| use super::model_pricing::{cost, model_pricing_for}; | ||
| use super::oauth; | ||
| use super::utils::{ | ||
| check_bedrock_context_length_error, check_openai_context_length_error, get_model, | ||
| messages_to_openai_spec, openai_response_to_message, tools_to_openai_spec, | ||
| }; | ||
| use super::utils::{check_bedrock_context_length_error, get_model}; | ||
| use crate::message::Message; | ||
| use crate::providers::openai_utils::{ | ||
| check_openai_context_length_error, messages_to_openai_spec, openai_response_to_message, | ||
| tools_to_openai_spec, | ||
| }; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: we should prob use the get_openai_usage and handle_response in this one as well.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| use mcp_core::tool::Tool; | ||
|
|
||
| pub struct DatabricksProvider { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,7 @@ use super::{ | |
| databricks::DatabricksProvider, google::GoogleProvider, ollama::OllamaProvider, | ||
| openai::OpenAiProvider, | ||
| }; | ||
| use crate::providers::groq::GroqProvider; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. prob move this up into the super |
||
| use anyhow::Result; | ||
| use strum_macros::EnumIter; | ||
|
|
||
|
|
@@ -13,6 +14,7 @@ pub enum ProviderType { | |
| Ollama, | ||
| Anthropic, | ||
| Google, | ||
| Groq, | ||
| } | ||
|
|
||
| pub fn get_provider(config: ProviderConfig) -> Result<Box<dyn Provider + Send + Sync>> { | ||
|
|
@@ -26,5 +28,6 @@ pub fn get_provider(config: ProviderConfig) -> Result<Box<dyn Provider + Send + | |
| Ok(Box::new(AnthropicProvider::new(anthropic_config)?)) | ||
| } | ||
| ProviderConfig::Google(google_config) => Ok(Box::new(GoogleProvider::new(google_config)?)), | ||
| ProviderConfig::Groq(groq_config) => Ok(Box::new(GroqProvider::new(groq_config)?)), | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| use crate::message::Message; | ||
| use crate::providers::base::{Provider, ProviderUsage, Usage}; | ||
| use crate::providers::configs::{GroqProviderConfig, ModelConfig, ProviderModelConfig}; | ||
| use crate::providers::openai_utils::{ | ||
| create_openai_request_payload, get_openai_usage, openai_response_to_message, | ||
| }; | ||
| use crate::providers::utils::{get_model, handle_response}; | ||
| use async_trait::async_trait; | ||
| use mcp_core::Tool; | ||
| use reqwest::Client; | ||
| use serde_json::Value; | ||
| use std::time::Duration; | ||
|
|
||
| pub const GROQ_API_HOST: &str = "https://api.groq.com"; | ||
| pub const GROQ_DEFAULT_MODEL: &str = "llama3-70b-8192"; | ||
|
|
||
| pub struct GroqProvider { | ||
| client: Client, | ||
| config: GroqProviderConfig, | ||
| } | ||
|
|
||
| impl GroqProvider { | ||
| pub fn new(config: GroqProviderConfig) -> anyhow::Result<Self> { | ||
| let client = Client::builder() | ||
| .timeout(Duration::from_secs(600)) // 10 minutes timeout | ||
| .build()?; | ||
|
|
||
| Ok(Self { client, config }) | ||
| } | ||
|
|
||
| fn get_usage(data: &Value) -> anyhow::Result<Usage> { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should consider adding get_usage as a trait for Providers in the base object
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. agree. This PR has many changes. I can create a follow-up PR after this PR is merged |
||
| get_openai_usage(data) | ||
| } | ||
|
|
||
| async fn post(&self, payload: Value) -> anyhow::Result<Value> { | ||
| let url = format!( | ||
| "{}/openai/v1/chat/completions", | ||
| self.config.host.trim_end_matches('/') | ||
| ); | ||
|
|
||
| let response = self | ||
| .client | ||
| .post(&url) | ||
| .header("Authorization", format!("Bearer {}", self.config.api_key)) | ||
| .json(&payload) | ||
| .send() | ||
| .await?; | ||
| handle_response(payload, response).await? | ||
| } | ||
| } | ||
|
|
||
| #[async_trait] | ||
| impl Provider for GroqProvider { | ||
| fn get_model_config(&self) -> &ModelConfig { | ||
| self.config.model_config() | ||
| } | ||
|
|
||
| async fn complete( | ||
| &self, | ||
| system: &str, | ||
| messages: &[Message], | ||
| tools: &[Tool], | ||
| ) -> anyhow::Result<(Message, ProviderUsage)> { | ||
| let payload = create_openai_request_payload(&self.config.model, system, messages, tools)?; | ||
|
|
||
| let response = self.post(payload).await?; | ||
|
|
||
| let message = openai_response_to_message(response.clone())?; | ||
| let usage = Self::get_usage(&response)?; | ||
| let model = get_model(&response); | ||
|
|
||
| Ok((message, ProviderUsage::new(model, usage, None))) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
one thing I missed in the google provider and here initially was that we also want to add context_limit and estimate_factor here as well