Skip to content

.NET: Align file tool descriptions with generated schema argument names - #7675

Open
Ruiming Zhao (uuzzrm) wants to merge 1 commit into
microsoft:mainfrom
uuzzrm:fix/align-harness-description-schema-names
Open

.NET: Align file tool descriptions with generated schema argument names#7675
Ruiming Zhao (uuzzrm) wants to merge 1 commit into
microsoft:mainfrom
uuzzrm:fix/align-harness-description-schema-names

Conversation

@uuzzrm

Copy link
Copy Markdown
Contributor

Motivation & Context

The file_access and file_memory tool descriptions refer to their arguments by snake_case names (glob_pattern, old_string, new_string, replace_all) while AIFunctionFactory generates the tool schema from the camelCase C# parameter names (globPattern, oldString, newString, replaceAll). A model that follows the description emits argument names that never bind, so file_access_ls runs without its filter and file_access_replace fails its own "old_string not found" check for reasons unrelated to the file.

Description & Review Guide

  • What are the major changes?
    Renamed the argument references in the [Description] text of the affected tools so they match the generated schema:

    • file_access_ls, file_memory_ls, file_memory_grep: glob_patternglobPattern
    • file_access_replace, file_memory_replace: old_string/new_string/replace_alloldString/newString/replaceAll
      The replace_lines descriptions are intentionally left alone: line_number and new_line are mapped explicitly via [JsonPropertyName] and are genuinely snake_case in the schema.
      Added FileAccessToolDescriptionSchemaTests and FileMemoryToolDescriptionSchemaTests asserting each affected description and its generated schema agree on argument names, plus a guard for the replace_lines names.
  • What is the impact of these changes?
    Models that follow the descriptions will emit argument names that bind, so filtering and replace behave as described instead of silently dropping arguments.

  • What do you want reviewers to focus on?
    That every affected tool is covered, and that the replace_lines JsonPropertyName names were intentionally kept as-is.

Related Issue

Fixes #7672

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR is linked to an issue and there is no other open PR for this issue (see Related Issue above).
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

The file_access and file_memory tool descriptions referenced arguments
by snake_case names (glob_pattern, old_string, new_string, replace_all)
while AIFunctionFactory generates the tool schema from the camelCase C#
parameter names. A model that follows the description ends up emitting
argument names that never bind, so filters were silently dropped and
replace calls failed for reasons unrelated to the file.

Renamed the references to match the schema (globPattern, oldString,
newString, replaceAll). The replace_lines descriptions are untouched:
line_number and new_line are explicitly mapped via JsonPropertyName and
are genuinely snake_case in the schema.

Added regression tests asserting that each affected tool description and
its generated schema agree on argument names for both providers.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds regression tests to ensure file tool descriptions reference the same argument names as the JSON schema generated by AIFunctionFactory, and updates tool [Description] strings to match the schema naming.

Changes:

  • Added unit tests validating tool description argument names for FileAccess and FileMemory tools.
  • Updated [Description] attributes in FileAccess/FileMemory providers to use schema-aligned camelCase argument names (e.g., globPattern, oldString).
  • Ensured explicitly-mapped snake_case argument names (via JsonPropertyName) remain referenced as-is in descriptions.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
dotnet/tests/Microsoft.Agents.AI.UnitTests/Harness/FileMemory/FileMemoryToolDescriptionSchemaTests.cs New tests asserting FileMemory tool descriptions match JSON schema parameter names.
dotnet/tests/Microsoft.Agents.AI.UnitTests/Harness/FileAccess/FileAccessToolDescriptionSchemaTests.cs New tests asserting FileAccess tool descriptions match JSON schema parameter names.
dotnet/src/Microsoft.Agents.AI/Harness/FileMemory/FileMemoryProvider.cs Updated tool descriptions to use schema argument names (globPattern, oldString, etc.).
dotnet/src/Microsoft.Agents.AI/Harness/FileAccess/FileAccessProvider.cs Updated tool descriptions to use schema argument names (globPattern, oldString, etc.).

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +71 to +123
private static async Task<AIFunction> GetToolAsync(string toolName)
{
// Arrange
var provider = new FileAccessProvider(new InMemoryAgentFileStore());
var agent = new Mock<AIAgent>().Object;
var session = new ChatClientAgentSession();
#pragma warning disable MAAI001
var context = new AIContextProvider.InvokingContext(agent, session, new AIContext());
#pragma warning restore MAAI001

AIContext result = await provider.InvokingAsync(context);
return (AIFunction)result.Tools!.First(t => t is AIFunction f && f.Name == toolName);
}

private static List<string> GetSchemaArgumentNames(AIFunction tool)
{
var names = new List<string>();
if (tool.JsonSchema is JsonElement schema)
{
CollectPropertyNames(schema, names);
}

return names.Distinct().ToList();
}

private static void CollectPropertyNames(JsonElement element, List<string> names)
{
if (element.ValueKind == JsonValueKind.Object)
{
foreach (JsonProperty property in element.EnumerateObject())
{
if (property.Name == "properties")
{
foreach (JsonProperty item in property.Value.EnumerateObject())
{
names.Add(item.Name);
CollectPropertyNames(item.Value, names);
}
}
else
{
CollectPropertyNames(property.Value, names);
}
}
}
else if (element.ValueKind == JsonValueKind.Array)
{
foreach (JsonElement item in element.EnumerateArray())
{
CollectPropertyNames(item, names);
}
}
}
Comment on lines +87 to +122
var names = new List<string>();
if (tool.JsonSchema is JsonElement schema)
{
CollectPropertyNames(schema, names);
}

return names.Distinct().ToList();
}

private static void CollectPropertyNames(JsonElement element, List<string> names)
{
if (element.ValueKind == JsonValueKind.Object)
{
foreach (JsonProperty property in element.EnumerateObject())
{
if (property.Name == "properties")
{
foreach (JsonProperty item in property.Value.EnumerateObject())
{
names.Add(item.Name);
CollectPropertyNames(item.Value, names);
}
}
else
{
CollectPropertyNames(property.Value, names);
}
}
}
else if (element.ValueKind == JsonValueKind.Array)
{
foreach (JsonElement item in element.EnumerateArray())
{
CollectPropertyNames(item, names);
}
}
#pragma warning restore MAAI001

AIContext result = await provider.InvokingAsync(context);
return (AIFunction)result.Tools!.First(t => t is AIFunction f && f.Name == toolName);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

.NET Usage: [Issues, PRs], Target: .Net

Projects

None yet

Development

Successfully merging this pull request may close these issues.

.NET: [Bug]: Harness file tool descriptions name arguments in snake_case, but the generated schema is camelCase

2 participants