Improve edit agent's knowledge of tools (#6356)

# Description of Changes
Give Edit Agent access to descriptions of the request from the Java API.
This opens the door to us better documenting our Java APIs to give the
stirling engine better knowledge of what the various tools are and how
to use them.

Also improves the tool selection sub-agent to get the tool parameters
and descriptions so it can more intelligently decide which operations
should be used to fulfil the user's request. Also provides it more
encouragement to string together multiple operations if necessary.
This commit is contained in:
James Brunton
2026-05-14 18:30:39 +00:00
committed by GitHub
parent ece1bb6865
commit beb99e273b
7 changed files with 536 additions and 239 deletions
+22 -5
View File
@@ -21,7 +21,7 @@ from datamodel_code_generator.format import Formatter
from referencing import Registry, Resource
from referencing.jsonschema import DRAFT202012
# Fields inherited from PDFFile base class not tool parameters.
# Fields inherited from PDFFile base class - not tool parameters.
BASE_CLASS_FIELDS = frozenset({"fileInput", "fileId"})
_ENGINE_ROOT = Path(__file__).resolve().parents[1]
@@ -73,8 +73,9 @@ class ToolDiscovery:
for path, path_item in sorted(self.spec.get("paths", {}).items()):
if "{" in path or not any(path.startswith(p) for p in self.ALLOWED_PATH_PREFIXES):
continue
body_props = self._get_request_properties(path_item) or {}
body_schema = self._get_request_body_schema(path_item) or {}
query_props = self._get_query_parameters(path_item)
body_props = body_schema.get("properties") or {}
# Body properties win on name collision — body is the canonical param source
# for the existing tools; query params are additive.
properties = {**query_props, **body_props}
@@ -87,7 +88,21 @@ class ToolDiscovery:
enum_name = _deduplicate(_path_to_enum_name(path), used_enum)
class_name = _deduplicate(_path_to_class_name(path), used_class)
defs[class_name] = {"type": "object", "properties": clean_props}
entry: dict[str, Any] = {
"type": "object",
"properties": clean_props,
"description": body_schema.get("description"),
}
# Calculate which fields are actually required (many are marked as required,
# but have a default set, so they're not really required)
required = [
name
for name in body_schema.get("required") or []
if name in clean_props and "default" not in (clean_props[name] or {})
]
if required:
entry["required"] = required
defs[class_name] = entry
tools.append(ToolSpec(path, enum_name, class_name))
self._inline_component_refs(defs)
@@ -119,7 +134,7 @@ class ToolDiscovery:
return self.resolver.lookup(schema["$ref"]).contents
return schema
def _get_request_properties(self, path_item: dict[str, Any]) -> dict[str, Any] | None:
def _get_request_body_schema(self, path_item: dict[str, Any]) -> dict[str, Any] | None:
post = path_item.get("post")
if not post:
return None
@@ -128,7 +143,7 @@ class ToolDiscovery:
if media_type in content:
schema = content[media_type].get("schema")
if schema:
return self._resolve_ref(schema).get("properties")
return self._resolve_ref(schema)
return None
def _get_query_parameters(self, path_item: dict[str, Any]) -> dict[str, Any]:
@@ -227,6 +242,8 @@ def generate_models_code(combined_schema: dict[str, Any]) -> str:
field_constraints=True,
no_alias=True,
set_default_enum_member=True,
strict_nullable=True,
use_schema_description=True,
additional_imports=["enum.StrEnum"],
enable_version_header=False,
custom_file_header=_FILE_HEADER,