Remove unnecessary fields from the tool schemas (#29381)

This PR removes two fields from JSON schemas (`$schema` and `title`),
which are not expected by any model provider, but were spuriously
included by our JSON schema library, `schemars`.

These added noise to requests and cost wasted input tokens.

### Old

```json
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "FetchToolInput",
  "type": "object",
  "required": [
    "url"
  ],
  "properties": {
    "url": {
      "description": "The URL to fetch.",
      "type": "string"
    }
  }
}
```

### New:

```json
{
  "properties": {
    "url": {
      "description": "The URL to fetch.",
      "type": "string"
    }
  },
  "required": [
    "url"
  ],
  "type": "object"
}
```

- N/A
This commit is contained in:
Max Brunsfeld 2025-04-24 18:09:25 -07:00 committed by GitHub
parent 17ecf94f6f
commit 57d8397f53
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 49 additions and 25 deletions

View file

@ -931,10 +931,8 @@ impl Thread {
let mut request = self.to_completion_request(cx); let mut request = self.to_completion_request(cx);
if model.supports_tools() { if model.supports_tools() {
request.tools = { request.tools = self
let mut tools = Vec::new(); .tools()
tools.extend(
self.tools()
.read(cx) .read(cx)
.enabled_tools(cx) .enabled_tools(cx)
.into_iter() .into_iter()
@ -946,11 +944,8 @@ impl Thread {
description: tool.description(), description: tool.description(),
input_schema, input_schema,
}) })
}), })
); .collect();
tools
};
} }
self.stream_completion(request, model, window, cx); self.stream_completion(request, model, window, cx);

View file

@ -10,6 +10,11 @@ pub fn adapt_schema_to_format(
json: &mut Value, json: &mut Value,
format: LanguageModelToolSchemaFormat, format: LanguageModelToolSchemaFormat,
) -> Result<()> { ) -> Result<()> {
if let Value::Object(obj) = json {
obj.remove("$schema");
obj.remove("title");
}
match format { match format {
LanguageModelToolSchemaFormat::JsonSchema => Ok(()), LanguageModelToolSchemaFormat::JsonSchema => Ok(()),
LanguageModelToolSchemaFormat::JsonSchemaSubset => adapt_to_json_schema_subset(json), LanguageModelToolSchemaFormat::JsonSchemaSubset => adapt_to_json_schema_subset(json),
@ -30,10 +35,7 @@ fn adapt_to_json_schema_subset(json: &mut Value) -> Result<()> {
} }
} }
const KEYS_TO_REMOVE: [&str; 2] = ["format", "$schema"]; obj.remove("format");
for key in KEYS_TO_REMOVE {
obj.remove(key);
}
if let Some(default) = obj.get("default") { if let Some(default) = obj.get("default") {
let is_null = default.is_null(); let is_null = default.is_null();

View file

@ -110,11 +110,38 @@ pub fn init(http_client: Arc<HttpClientWithUrl>, cx: &mut App) {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
use client::Client; use client::Client;
use clock::FakeSystemClock; use clock::FakeSystemClock;
use http_client::FakeHttpClient; use http_client::FakeHttpClient;
use schemars::JsonSchema;
use serde::Serialize;
use super::*; #[test]
fn test_json_schema() {
#[derive(Serialize, JsonSchema)]
struct GetWeatherTool {
location: String,
}
let schema = schema::json_schema_for::<GetWeatherTool>(
language_model::LanguageModelToolSchemaFormat::JsonSchema,
)
.unwrap();
assert_eq!(
schema,
serde_json::json!({
"type": "object",
"properties": {
"location": {
"type": "string"
}
},
"required": ["location"],
})
);
}
#[gpui::test] #[gpui::test]
fn test_builtin_tool_schema_compatibility(cx: &mut App) { fn test_builtin_tool_schema_compatibility(cx: &mut App) {