eval: Improve `StreamingEditFileTool` performance (#52428)

Bennet Bo Fenner and Ben Brandt created

## Context

| Eval | Score |
|------|-------|
| eval_delete_function | 1.00 |
| eval_extract_handle_command_output | 0.96 |
| eval_translate_doc_comments | 0.96 |

Porting the rest of the evals is still a todo.

## Self-Review Checklist

<!-- Check before requesting review: -->
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- N/A

---------

Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>

Change summary

crates/agent/src/tools/evals/fixtures/extract_handle_command_output/possible-09.diff | 20 
crates/agent/src/tools/evals/streaming_edit_file.rs                                  |  2 
crates/agent/src/tools/streaming_edit_file_tool.rs                                   |  2 
crates/language_model/src/tool_schema.rs                                             |  7 
4 files changed, 30 insertions(+), 1 deletion(-)

Detailed changes

crates/agent/src/tools/evals/fixtures/extract_handle_command_output/possible-09.diff 🔗

@@ -0,0 +1,20 @@
+@@ -5,7 +5,7 @@
+ use futures::AsyncWriteExt;
+ use gpui::SharedString;
+ use serde::{Deserialize, Serialize};
+-use std::process::Stdio;
++use std::process::{Output, Stdio};
+ use std::{ops::Range, path::Path};
+ use text::Rope;
+ use time::OffsetDateTime;
+@@ -94,6 +94,10 @@
+
+     let output = child.output().await.context("reading git blame output")?;
+
++    handle_command_output(output)
++}
++
++fn handle_command_output(output: Output) -> Result<String> {
+     if !output.status.success() {
+         let stderr = String::from_utf8_lossy(&output.stderr);
+         let trimmed = stderr.trim();

crates/agent/src/tools/evals/streaming_edit_file.rs 🔗

@@ -808,6 +808,8 @@ fn eval_extract_handle_command_output() {
         include_str!("fixtures/extract_handle_command_output/possible-05.diff"),
         include_str!("fixtures/extract_handle_command_output/possible-06.diff"),
         include_str!("fixtures/extract_handle_command_output/possible-07.diff"),
+        include_str!("fixtures/extract_handle_command_output/possible-08.diff"),
+        include_str!("fixtures/extract_handle_command_output/possible-09.diff"),
     ];
 
     eval_utils::eval(100, 0.95, eval_utils::NoProcessor, move || {

crates/agent/src/tools/streaming_edit_file_tool.rs 🔗

@@ -111,6 +111,8 @@ pub enum StreamingEditFileMode {
 }
 
 /// A single edit operation that replaces old text with new text
+/// Properly escape all text fields as valid JSON strings.
+/// Remember to escape special characters like newlines (`\n`) and quotes (`"`) in JSON strings.
 #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
 pub struct Edit {
     /// The exact text to find in the file. This will be matched using fuzzy matching

crates/language_model/src/tool_schema.rs 🔗

@@ -17,7 +17,12 @@ pub enum LanguageModelToolSchemaFormat {
 
 pub fn root_schema_for<T: JsonSchema>(format: LanguageModelToolSchemaFormat) -> Schema {
     let mut generator = match format {
-        LanguageModelToolSchemaFormat::JsonSchema => SchemaSettings::draft07().into_generator(),
+        LanguageModelToolSchemaFormat::JsonSchema => SchemaSettings::draft07()
+            .with(|settings| {
+                settings.meta_schema = None;
+                settings.inline_subschemas = true;
+            })
+            .into_generator(),
         LanguageModelToolSchemaFormat::JsonSchemaSubset => SchemaSettings::openapi3()
             .with(|settings| {
                 settings.meta_schema = None;