Fix Ollama timeouts broken on Preview (#18449)

Peter Tripp and Vladimir Bulyga created

Supersedes: https://github.com/zed-industries/zed/pull/18310
See also: https://github.com/zed-industries/zed/issues/18304

This PR targets v0.155.x and is a hotfix for Preview.

Signed-off-by: Vladimir Bulyga <zero@13w.me>
Co-authored-by: Vladimir Bulyga <zero@13w.me>

Change summary

Cargo.lock                  | 1 +
crates/ollama/Cargo.toml    | 1 +
crates/ollama/src/ollama.rs | 9 +++++++--
3 files changed, 9 insertions(+), 2 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -7523,6 +7523,7 @@ dependencies = [
  "anyhow",
  "futures 0.3.30",
  "http_client",
+ "isahc",
  "schemars",
  "serde",
  "serde_json",

crates/ollama/Cargo.toml 🔗

@@ -19,6 +19,7 @@ schemars = ["dep:schemars"]
 anyhow.workspace = true
 futures.workspace = true
 http_client.workspace = true
+isahc.workspace = true
 schemars = { workspace = true, optional = true }
 serde.workspace = true
 serde_json.workspace = true

crates/ollama/src/ollama.rs 🔗

@@ -1,6 +1,7 @@
 use anyhow::{anyhow, Context, Result};
 use futures::{io::BufReader, stream::BoxStream, AsyncBufReadExt, AsyncReadExt, StreamExt};
 use http_client::{http, AsyncBody, HttpClient, Method, Request as HttpRequest};
+use isahc::config::Configurable;
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
 use serde_json::{value::RawValue, Value};
@@ -262,14 +263,18 @@ pub async fn stream_chat_completion(
     client: &dyn HttpClient,
     api_url: &str,
     request: ChatRequest,
-    _: Option<Duration>,
+    low_speed_timeout: Option<Duration>,
 ) -> Result<BoxStream<'static, Result<ChatResponseDelta>>> {
     let uri = format!("{api_url}/api/chat");
-    let request_builder = http::Request::builder()
+    let mut request_builder = http::Request::builder()
         .method(Method::POST)
         .uri(uri)
         .header("Content-Type", "application/json");
 
+    if let Some(low_speed_timeout) = low_speed_timeout {
+        request_builder = request_builder.low_speed_timeout(100, low_speed_timeout);
+    };
+
     let request = request_builder.body(AsyncBody::from(serde_json::to_string(&request)?))?;
     let mut response = client.send(request).await?;
     if response.status().is_success() {