diff --git a/crates/goose/src/providers/githubcopilot.rs b/crates/goose/src/providers/githubcopilot.rs index 6119783ec959..685a603fddff 100644 --- a/crates/goose/src/providers/githubcopilot.rs +++ b/crates/goose/src/providers/githubcopilot.rs @@ -132,6 +132,29 @@ pub struct GithubCopilotProvider { } impl GithubCopilotProvider { + fn payload_contains_image(payload: &Value) -> bool { + payload + .get("messages") + .and_then(|m| m.as_array()) + .is_some_and(|messages| { + messages.iter().any(|msg| { + msg.get("content").is_some_and(|content| { + content + .as_array() + .map(|arr| arr.iter().collect::>()) + .unwrap_or_else(|| vec![content]) + .iter() + .any(|item| { + matches!( + item.get("type").and_then(|v| v.as_str()), + Some("image_url") | Some("image") + ) + }) + }) + }) + }) + } + pub async fn from_env(model: ModelConfig) -> Result { let client = Client::builder() .timeout(Duration::from_secs(600)) @@ -164,14 +187,21 @@ impl GithubCopilotProvider { let (endpoint, token) = self.get_api_info().await?; let url = url::Url::parse(&format!("{}/chat/completions", endpoint)) .map_err(|e| ProviderError::RequestFailed(format!("Invalid base URL: {e}")))?; - let response = self + + let headers = self.get_github_headers(); + + let mut request = self .client .post(url) - .headers(self.get_github_headers()) - .header("Authorization", format!("Bearer {}", token)) - .json(payload) - .send() - .await?; + .headers(headers) + .header("Authorization", format!("Bearer {}", token)); + + if Self::payload_contains_image(payload) { + request = request.header("Copilot-Vision-Request", "true"); + } + + let response = request.json(payload).send().await?; + if stream_only_model { let mut collector = OAIStreamCollector::new(); let mut stream = response.bytes_stream();