feat: Gemini OAuth provider (#8129)
Signed-off-by: Michael Neale <michael.neale@gmail.com>
This commit is contained in:
@@ -46,6 +46,7 @@ fn map_provider_name(provider: &str) -> &str {
|
||||
"azure_openai" => "azure",
|
||||
"aws_bedrock" => "amazon-bedrock",
|
||||
"gcp_vertex_ai" => "google-vertex",
|
||||
"gemini_oauth" => "google",
|
||||
_ => provider,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
use anyhow::Result;
|
||||
use futures::future::BoxFuture;
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::acp::{
|
||||
extension_configs_to_mcp_servers, AcpProvider, AcpProviderConfig, PermissionMapping,
|
||||
ACP_CURRENT_MODEL,
|
||||
};
|
||||
use crate::config::search_path::SearchPaths;
|
||||
use crate::config::{Config, GooseMode};
|
||||
use crate::model::ModelConfig;
|
||||
use crate::providers::base::{ProviderDef, ProviderMetadata};
|
||||
|
||||
const GEMINI_ACP_PROVIDER_NAME: &str = "gemini-acp";
|
||||
const GEMINI_ACP_DOC_URL: &str = "https://github.com/google-gemini/gemini-cli";
|
||||
|
||||
pub struct GeminiAcpProvider;
|
||||
|
||||
impl ProviderDef for GeminiAcpProvider {
|
||||
type Provider = AcpProvider;
|
||||
|
||||
fn metadata() -> ProviderMetadata {
|
||||
ProviderMetadata::new(
|
||||
GEMINI_ACP_PROVIDER_NAME,
|
||||
"Gemini CLI (ACP)",
|
||||
"Use goose with your Google Gemini subscription via the Gemini CLI.",
|
||||
ACP_CURRENT_MODEL,
|
||||
vec![],
|
||||
GEMINI_ACP_DOC_URL,
|
||||
vec![],
|
||||
)
|
||||
.with_setup_steps(vec![
|
||||
"Install the Gemini CLI: `npm install -g @google/gemini-cli`",
|
||||
"Run `gemini` once to authenticate with your Google account",
|
||||
"Set in your goose config file (`~/.config/goose/config.yaml` on macOS/Linux):\n GOOSE_PROVIDER: gemini-acp\n GOOSE_MODEL: current",
|
||||
"Restart goose for changes to take effect",
|
||||
])
|
||||
}
|
||||
|
||||
fn from_env(
|
||||
model: ModelConfig,
|
||||
extensions: Vec<crate::config::ExtensionConfig>,
|
||||
) -> BoxFuture<'static, Result<AcpProvider>> {
|
||||
Box::pin(async move {
|
||||
let config = Config::global();
|
||||
let command_name: String = config.get_gemini_cli_command().unwrap_or_default().into();
|
||||
let resolved_command = SearchPaths::builder().with_npm().resolve(&command_name)?;
|
||||
let goose_mode = config.get_goose_mode().unwrap_or(GooseMode::Auto);
|
||||
|
||||
let permission_mapping = PermissionMapping {
|
||||
allow_option_id: Some("allow".to_string()),
|
||||
reject_option_id: Some("reject".to_string()),
|
||||
rejected_tool_status: sacp::schema::ToolCallStatus::Failed,
|
||||
};
|
||||
|
||||
let mut args = vec!["--acp".to_string()];
|
||||
if model.model_name != ACP_CURRENT_MODEL {
|
||||
args.push("--model".to_string());
|
||||
args.push(model.model_name.clone());
|
||||
}
|
||||
|
||||
let mode_mapping = HashMap::from([
|
||||
(GooseMode::Auto, "yolo".to_string()),
|
||||
(GooseMode::Approve, "default".to_string()),
|
||||
(GooseMode::SmartApprove, "auto_edit".to_string()),
|
||||
(GooseMode::Chat, "plan".to_string()),
|
||||
]);
|
||||
|
||||
let provider_config = AcpProviderConfig {
|
||||
command: resolved_command,
|
||||
args,
|
||||
env: vec![],
|
||||
env_remove: vec![],
|
||||
work_dir: std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")),
|
||||
mcp_servers: extension_configs_to_mcp_servers(&extensions),
|
||||
session_mode_id: Some(mode_mapping[&goose_mode].clone()),
|
||||
mode_mapping,
|
||||
permission_mapping,
|
||||
notification_callback: None,
|
||||
};
|
||||
|
||||
let metadata = Self::metadata();
|
||||
AcpProvider::connect(metadata.name, model, goose_mode, provider_config).await
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -161,7 +161,7 @@ impl ProviderDef for GeminiCliProvider {
|
||||
ProviderMetadata::new(
|
||||
GEMINI_CLI_PROVIDER_NAME,
|
||||
"Gemini CLI",
|
||||
"[Deprecated: use gemini-acp instead] Execute Gemini models via gemini CLI tool. Requires gemini CLI installed.",
|
||||
"[Deprecated: use gemini_oauth instead] Execute Gemini models via gemini CLI tool. Requires gemini CLI installed.",
|
||||
GEMINI_CLI_DEFAULT_MODEL,
|
||||
GEMINI_CLI_KNOWN_MODELS.to_vec(),
|
||||
GEMINI_CLI_DOC_URL,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -111,7 +111,7 @@ impl ProviderDef for GoogleProvider {
|
||||
fn metadata() -> ProviderMetadata {
|
||||
ProviderMetadata::new(
|
||||
GOOGLE_PROVIDER_NAME,
|
||||
"Google Gemini",
|
||||
"Google Gemini (API Key)",
|
||||
"Gemini models from Google AI",
|
||||
GOOGLE_DEFAULT_MODEL,
|
||||
GOOGLE_KNOWN_MODELS.to_vec(),
|
||||
|
||||
@@ -19,8 +19,8 @@ use super::{
|
||||
cursor_agent::CursorAgentProvider,
|
||||
databricks::DatabricksProvider,
|
||||
gcpvertexai::GcpVertexAIProvider,
|
||||
gemini_acp::GeminiAcpProvider,
|
||||
gemini_cli::GeminiCliProvider,
|
||||
gemini_oauth::GeminiOAuthProvider,
|
||||
githubcopilot::GithubCopilotProvider,
|
||||
google::GoogleProvider,
|
||||
litellm::LiteLLMProvider,
|
||||
@@ -57,7 +57,6 @@ async fn init_registry() -> RwLock<ProviderRegistry> {
|
||||
registry.register::<LocalInferenceProvider>(false);
|
||||
registry.register::<ChatGptCodexProvider>(true);
|
||||
registry.register::<ClaudeAcpProvider>(false);
|
||||
registry.register::<GeminiAcpProvider>(false);
|
||||
registry.register::<ClaudeCodeProvider>(true);
|
||||
registry.register::<CodexAcpProvider>(false);
|
||||
registry.register::<CodexProvider>(true);
|
||||
@@ -65,6 +64,7 @@ async fn init_registry() -> RwLock<ProviderRegistry> {
|
||||
registry.register::<DatabricksProvider>(true);
|
||||
registry.register::<GcpVertexAIProvider>(false);
|
||||
registry.register::<GeminiCliProvider>(false);
|
||||
registry.register::<GeminiOAuthProvider>(true);
|
||||
registry.register::<GithubCopilotProvider>(false);
|
||||
registry.register::<GoogleProvider>(true);
|
||||
registry.register::<LiteLLMProvider>(false);
|
||||
|
||||
@@ -21,8 +21,8 @@ pub mod errors;
|
||||
pub mod formats;
|
||||
mod gcpauth;
|
||||
pub mod gcpvertexai;
|
||||
pub mod gemini_acp;
|
||||
pub mod gemini_cli;
|
||||
pub mod gemini_oauth;
|
||||
pub mod githubcopilot;
|
||||
pub mod google;
|
||||
mod init;
|
||||
|
||||
@@ -892,18 +892,6 @@ async fn test_codex_acp_provider() -> Result<()> {
|
||||
.await
|
||||
}
|
||||
|
||||
// Requires: npm install -g @google/gemini-cli
|
||||
#[tokio::test]
|
||||
async fn test_gemini_acp_provider() -> Result<()> {
|
||||
// Don't run tests with ACP_CURRENT_MODEL, as gemini sets "auto-gemini-3" even when the user
|
||||
// has no access to the Preview Release Channel, resulting in "Requested entity was not found."
|
||||
// See https://github.com/google-gemini/gemini-cli/issues/22803
|
||||
ProviderTestConfig::with_agentic_provider("gemini-acp", "auto-gemini-2.5", "gemini")
|
||||
.model_switch_name("gemini-2.5-flash")
|
||||
.run()
|
||||
.await
|
||||
}
|
||||
|
||||
#[ctor::dtor]
|
||||
fn print_test_report() {
|
||||
TEST_REPORT.print_summary();
|
||||
|
||||
Reference in New Issue
Block a user