diff --git a/crates/goose/src/providers/githubcopilot.rs b/crates/goose/src/providers/githubcopilot.rs index 1f29a8980752..239163bc7d41 100644 --- a/crates/goose/src/providers/githubcopilot.rs +++ b/crates/goose/src/providers/githubcopilot.rs @@ -426,4 +426,45 @@ impl Provider for GithubCopilotProvider { emit_debug_trace(&self.model, &payload, &response, &usage); Ok((message, ProviderUsage::new(model, usage))) } + + /// Fetch supported models from GitHub Copliot; returns Err on failure, Ok(None) if not present + async fn fetch_supported_models_async(&self) -> Result>, ProviderError> { + let (endpoint, token) = self.get_api_info().await?; + let url = format!("{}/models", endpoint); + + let mut headers = http::HeaderMap::new(); + headers.insert(http::header::ACCEPT, "application/json".parse().unwrap()); + headers.insert( + http::header::CONTENT_TYPE, + "application/json".parse().unwrap(), + ); + headers.insert("Copilot-Integration-Id", "vscode-chat".parse().unwrap()); + headers.insert( + http::header::AUTHORIZATION, + format!("Bearer {}", token).parse().unwrap(), + ); + + let response = self.client.get(url).headers(headers).send().await?; + + let json: serde_json::Value = response.json().await?; + + let arr = match json.get("data").and_then(|v| v.as_array()) { + Some(arr) => arr, + None => return Ok(None), + }; + let mut models: Vec = arr + .iter() + .filter_map(|m| { + if let Some(s) = m.as_str() { + Some(s.to_string()) + } else if let Some(obj) = m.as_object() { + obj.get("id").and_then(|v| v.as_str()).map(str::to_string) + } else { + None + } + }) + .collect(); + models.sort(); + Ok(Some(models)) + } }