Change `tool_calls` to be an Option in response (#13778)

Allison Durham created

Here is an image of my now getting assistance responses!

![2024-07-03_08-45-37_swappy](https://github.com/zed-industries/zed/assets/20910163/904adc51-cb40-4622-878e-f679e0212426)

I ended up adding a function to handle the use case of not serializing
the tool_calls response if it is either null or empty to keep the
functionality of the existing implementation (not deserializing if vec
is empty). I'm sorta a noob, so happy to make changes if this isn't done
correctly, although it does work and it does pass tests!

Thanks a bunch to [amtoaer](https://github.com/amtoaer) for pointing me
in the direction on how to fix it.

Release Notes:

- Fixed some responses being dropped from OpenAI-compatible providers
([#13741](https://github.com/zed-industries/zed/issues/13741)).

Change summary

crates/collab/src/rpc.rs      | 1 +
crates/open_ai/src/open_ai.rs | 8 ++++++--
2 files changed, 7 insertions(+), 2 deletions(-)

Detailed changes

crates/collab/src/rpc.rs 🔗

@@ -4462,6 +4462,7 @@ async fn complete_with_open_ai(
                         tool_calls: choice
                             .delta
                             .tool_calls
+                            .unwrap_or_default()
                             .into_iter()
                             .map(|delta| proto::ToolCallDelta {
                                 index: delta.index as u32,

crates/open_ai/src/open_ai.rs 🔗

@@ -9,6 +9,10 @@ use strum::EnumIter;
 
 pub const OPEN_AI_API_URL: &str = "https://api.openai.com/v1";
 
+fn is_none_or_empty<T: AsRef<[U]>, U>(opt: &Option<T>) -> bool {
+    opt.as_ref().map_or(true, |v| v.as_ref().is_empty())
+}
+
 #[derive(Clone, Copy, Serialize, Deserialize, Debug, Eq, PartialEq)]
 #[serde(rename_all = "lowercase")]
 pub enum Role {
@@ -182,8 +186,8 @@ pub struct FunctionContent {
 pub struct ResponseMessageDelta {
     pub role: Option<Role>,
     pub content: Option<String>,
-    #[serde(default, skip_serializing_if = "Vec::is_empty")]
-    pub tool_calls: Vec<ToolCallChunk>,
+    #[serde(default, skip_serializing_if = "is_none_or_empty")]
+    pub tool_calls: Option<Vec<ToolCallChunk>>,
 }
 
 #[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]