diff --git a/dotnet/src/Microsoft.Agents.AI/Skills/File/AgentFileSkill.cs b/dotnet/src/Microsoft.Agents.AI/Skills/File/AgentFileSkill.cs
index d1c792de21..8a74fa034e 100644
--- a/dotnet/src/Microsoft.Agents.AI/Skills/File/AgentFileSkill.cs
+++ b/dotnet/src/Microsoft.Agents.AI/Skills/File/AgentFileSkill.cs
@@ -49,14 +49,13 @@ public sealed class AgentFileSkill : AgentSkill
///
///
/// Returns the raw SKILL.md content. When the skill has scripts, a
- /// <scripts><script name="..."><parameters_schema>...</parameters_schema></script></scripts>
- /// block is appended with a per-script entry describing the expected argument format.
+ /// <script_schemas> block is appended describing the argument format.
/// The result is cached after the first access.
///
public override ValueTask GetContentAsync(CancellationToken cancellationToken = default)
{
var content = this._content ??= this._scripts is { Count: > 0 }
- ? this._originalContent + AgentInlineSkillContentBuilder.BuildScriptsBlock(this._scripts)
+ ? this._originalContent + AgentInlineSkillContentBuilder.BuildScriptSchemasBlock(this._scripts)
: this._originalContent;
return new(content);
}
diff --git a/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentClassSkill.cs b/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentClassSkill.cs
index 32f461e32a..84174154a2 100644
--- a/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentClassSkill.cs
+++ b/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentClassSkill.cs
@@ -114,7 +114,6 @@ public abstract class AgentClassSkill<
this.Frontmatter.Name,
this.Frontmatter.Description,
this.Instructions,
- this.Resources,
this.Scripts));
}
@@ -147,11 +146,17 @@ public abstract class AgentClassSkill<
/// Gets the resources associated with this skill, or if none.
///
///
+ ///
/// The default implementation returns resources discovered via reflection by scanning
/// for members annotated with .
/// This discovery is compatible with Native AOT because is annotated with
/// . The result is cached after the first access.
/// Override this property in derived classes to provide skill-specific resources.
+ ///
+ ///
+ /// Resources are not automatically included in the skill body.
+ /// To enable discovery, reference resources by name in the skill's instructions or in other resources.
+ ///
///
public virtual IReadOnlyList? Resources => this._resources.Value;
@@ -159,11 +164,17 @@ public abstract class AgentClassSkill<
/// Gets the scripts associated with this skill, or if none.
///
///
+ ///
/// The default implementation returns scripts discovered via reflection by scanning
/// for methods annotated with .
/// This discovery is compatible with Native AOT because is annotated with
/// . The result is cached after the first access.
/// Override this property in derived classes to provide skill-specific scripts.
+ ///
+ ///
+ /// Only script parameter schemas are included in the skill body (as a <script_schemas> block).
+ /// To enable discovery, reference scripts by name in the skill's instructions or in a resource.
+ ///
///
public virtual IReadOnlyList? Scripts => this._scripts.Value;
@@ -184,6 +195,10 @@ public abstract class AgentClassSkill<
///
/// Creates a skill resource backed by a static value.
///
+ ///
+ /// Resources are not automatically included in the skill body.
+ /// To enable discovery, reference the resource by name in the skill's instructions or in another resource.
+ ///
/// The resource name.
/// The static resource value.
/// An optional description of the resource.
@@ -194,6 +209,10 @@ public abstract class AgentClassSkill<
///
/// Creates a skill resource backed by a delegate that produces a dynamic value.
///
+ ///
+ /// Resources are not automatically included in the skill body.
+ /// To enable discovery, reference the resource by name in the skill's instructions or in another resource.
+ ///
/// The resource name.
/// A method that produces the resource value when requested.
/// An optional description of the resource.
@@ -208,6 +227,10 @@ public abstract class AgentClassSkill<
///
/// Creates a skill script backed by a delegate.
///
+ ///
+ /// Only the script's parameter schema is included in the skill body (as a <script_schemas> block).
+ /// To enable discovery, reference the script by name in the skill's instructions or in a resource.
+ ///
/// The script name.
/// A method to execute when the script is invoked.
/// An optional description of the script.
diff --git a/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentInlineSkill.cs b/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentInlineSkill.cs
index 4fb2b045cb..2465431622 100644
--- a/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentInlineSkill.cs
+++ b/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentInlineSkill.cs
@@ -95,7 +95,7 @@ public sealed class AgentInlineSkill : AgentSkill
///
public override ValueTask GetContentAsync(CancellationToken cancellationToken = default)
{
- return new(this._cachedContent ??= AgentInlineSkillContentBuilder.Build(this.Frontmatter.Name, this.Frontmatter.Description, this._instructions, this._resources, this._scripts));
+ return new(this._cachedContent ??= AgentInlineSkillContentBuilder.Build(this.Frontmatter.Name, this.Frontmatter.Description, this._instructions, this._scripts));
}
///
@@ -115,6 +115,10 @@ public sealed class AgentInlineSkill : AgentSkill
///
/// Registers a static resource with this skill.
///
+ ///
+ /// Resources are not automatically included in the skill body.
+ /// To enable discovery, reference the resource by name in the skill's instructions or in another resource.
+ ///
/// The resource name.
/// The static resource value.
/// An optional description of the resource.
@@ -129,6 +133,10 @@ public sealed class AgentInlineSkill : AgentSkill
/// Registers a dynamic resource with this skill, backed by a C# delegate.
/// The delegate's parameters and return type are automatically marshaled via AIFunctionFactory.
///
+ ///
+ /// Resources are not automatically included in the skill body.
+ /// To enable discovery, reference the resource by name in the skill's instructions or in another resource.
+ ///
/// The resource name.
/// A method that produces the resource value when requested.
/// An optional description of the resource.
@@ -147,6 +155,10 @@ public sealed class AgentInlineSkill : AgentSkill
/// Registers a script with this skill, backed by a C# delegate.
/// The delegate's parameters and return type are automatically marshaled via AIFunctionFactory.
///
+ ///
+ /// Only the script's parameter schema is included in the skill body (as a <script_schemas> block).
+ /// To enable discovery, reference the script by name in the skill's instructions or in a resource.
+ ///
/// The script name.
/// A method to execute when the script is invoked.
/// An optional description of the script.
diff --git a/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentInlineSkillContentBuilder.cs b/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentInlineSkillContentBuilder.cs
index dabf75fa1a..d2f27edadc 100644
--- a/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentInlineSkillContentBuilder.cs
+++ b/dotnet/src/Microsoft.Agents.AI/Skills/Programmatic/AgentInlineSkillContentBuilder.cs
@@ -12,19 +12,17 @@ namespace Microsoft.Agents.AI;
internal static class AgentInlineSkillContentBuilder
{
///
- /// Builds the complete skill content containing name, description, instructions, resources, and scripts.
+ /// Builds the complete skill content containing name, description, instructions, and script parameter schemas.
///
/// The skill name.
/// The skill description.
/// The raw instructions text.
- /// Optional resources associated with the skill.
/// Optional scripts associated with the skill.
/// An XML-structured content string.
public static string Build(
string name,
string description,
string instructions,
- IReadOnlyList? resources,
IReadOnlyList? scripts)
{
_ = Throw.IfNullOrWhitespace(name);
@@ -39,41 +37,24 @@ internal static class AgentInlineSkillContentBuilder
.Append(EscapeXmlString(instructions))
.Append("\n");
- if (resources is { Count: > 0 })
- {
- sb.Append("\n\n\n");
- foreach (var resource in resources)
- {
- if (resource.Description is not null)
- {
- sb.Append($" \n");
- }
- else
- {
- sb.Append($" \n");
- }
- }
-
- sb.Append("");
- }
-
if (scripts is { Count: > 0 })
{
sb.Append('\n');
- sb.Append(BuildScriptsBlock(scripts));
+ sb.Append(BuildScriptSchemasBlock(scripts));
}
return sb.ToString();
}
///
- /// Builds a <scripts>...</scripts> XML block for the given scripts.
- /// Each script is emitted as a <script name="..."> element with optional
- /// description attribute and <parameters_schema> child element.
+ /// Builds a <script_schemas>...</script_schemas> XML block for the given scripts.
+ /// Each script is emitted as a <schema script="..."> element containing only
+ /// the parameter schema. This block serves as a reference for the model to know how to
+ /// format arguments when calling scripts, not as a discovery mechanism.
///
/// The scripts to include in the block.
- /// An XML string starting with \n<scripts>, or an empty string if the list is empty.
- public static string BuildScriptsBlock(IReadOnlyList scripts)
+ /// An XML string starting with \n<script_schemas>, or an empty string if the list is empty.
+ public static string BuildScriptSchemasBlock(IReadOnlyList scripts)
{
_ = Throw.IfNull(scripts);
@@ -83,32 +64,23 @@ internal static class AgentInlineSkillContentBuilder
}
var sb = new StringBuilder();
- sb.Append("\n\n");
+ sb.Append("\n\n");
foreach (var script in scripts)
{
var parametersSchema = script.ParametersSchema;
- if (script.Description is null && parametersSchema is null)
+ if (parametersSchema is null)
{
- sb.Append($" \n");
+ sb.Append($" {EscapeXmlString(parametersSchema.Value.GetRawText(), preserveQuotes: true)}\n");
}
}
- sb.Append("");
+ sb.Append("");
return sb.ToString();
}
diff --git a/dotnet/tests/Microsoft.Agents.AI.UnitTests/AgentSkills/AgentClassSkillTests.cs b/dotnet/tests/Microsoft.Agents.AI.UnitTests/AgentSkills/AgentClassSkillTests.cs
index 1248866a52..17bf71a388 100644
--- a/dotnet/tests/Microsoft.Agents.AI.UnitTests/AgentSkills/AgentClassSkillTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.UnitTests/AgentSkills/AgentClassSkillTests.cs
@@ -51,9 +51,8 @@ public sealed class AgentClassSkillTests
// Act & Assert — Content is cached
Assert.Same(await skill.GetContentAsync(), await skill.GetContentAsync());
- // Act & Assert — Content includes parameter schema from typed script
- Assert.Contains("parameters_schema", await skill.GetContentAsync());
- Assert.Contains("value", await skill.GetContentAsync());
+ // Act & Assert — Content includes parameter schema from typed script (with preserved quotes)
+ Assert.Contains("\"value\"", await skill.GetContentAsync());
}
[Fact]
@@ -383,10 +382,9 @@ public sealed class AgentClassSkillTests
// Arrange
var skill = new AttributedFullSkill();
- // Act & Assert — Content includes reflected resources and scripts
- Assert.Contains("", await skill.GetContentAsync());
- Assert.Contains("conversion-table", await skill.GetContentAsync());
- Assert.Contains("", await skill.GetContentAsync());
+ // Act & Assert — Content no longer includes resources in body; scripts are in script_schemas
+ Assert.DoesNotContain("", await skill.GetContentAsync());
+ Assert.Contains("", await skill.GetContentAsync());
Assert.Contains("convert", await skill.GetContentAsync());
// Act & Assert — discovered members are cached
@@ -504,7 +502,7 @@ public sealed class AgentClassSkillTests
}
[Fact]
- public async Task Content_IncludesDescription_ForReflectedResourcesAsync()
+ public async Task Content_DoesNotRenderResources_InBodyAsync()
{
// Arrange
var skill = new AttributedResourcePropertiesSkill();
@@ -512,8 +510,8 @@ public sealed class AgentClassSkillTests
// Act
var content = await skill.GetContentAsync();
- // Assert — descriptions from [Description] attribute appear in synthesized content
- Assert.Contains("Some important data.", content);
+ // Assert — resources are no longer rendered in body content
+ Assert.DoesNotContain("", content);
}
[Fact]
diff --git a/dotnet/tests/Microsoft.Agents.AI.UnitTests/AgentSkills/AgentFileSkillScriptTests.cs b/dotnet/tests/Microsoft.Agents.AI.UnitTests/AgentSkills/AgentFileSkillScriptTests.cs
index 9a27528051..aa001fd2a0 100644
--- a/dotnet/tests/Microsoft.Agents.AI.UnitTests/AgentSkills/AgentFileSkillScriptTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.UnitTests/AgentSkills/AgentFileSkillScriptTests.cs
@@ -122,11 +122,10 @@ public sealed class AgentFileSkillScriptTests
// Assert — content starts with original and appends per-script entries
Assert.StartsWith("Original content", content);
- Assert.Contains("", content);
- Assert.Contains("", content);
+ Assert.Contains("", content);
+ Assert.Contains("", content);
+ Assert.Contains("", content);
+ Assert.Contains("", content);
}
[Fact]
diff --git a/dotnet/tests/Microsoft.Agents.AI.UnitTests/AgentSkills/AgentInlineSkillTests.cs b/dotnet/tests/Microsoft.Agents.AI.UnitTests/AgentSkills/AgentInlineSkillTests.cs
index c6ae2212bf..d5b04d5653 100644
--- a/dotnet/tests/Microsoft.Agents.AI.UnitTests/AgentSkills/AgentInlineSkillTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.UnitTests/AgentSkills/AgentInlineSkillTests.cs
@@ -149,7 +149,7 @@ public sealed class AgentInlineSkillTests
}
[Fact]
- public async Task Content_IncludesResourcesAddedBeforeFirstAccessAsync()
+ public async Task Content_DoesNotIncludeResourcesInBodyAsync()
{
// Arrange
var skill = new AgentInlineSkill("my-skill", "A valid skill.", "Instructions.");
@@ -158,13 +158,12 @@ public sealed class AgentInlineSkillTests
// Act
var content = await skill.GetContentAsync();
- // Assert
- Assert.Contains("", content);
- Assert.Contains("config", content);
+ // Assert — resources are no longer rendered in the body; they're accessed via GetResourceAsync
+ Assert.DoesNotContain("", content);
}
[Fact]
- public async Task Content_IncludesDelegateResourcesAddedBeforeFirstAccessAsync()
+ public async Task Content_DoesNotIncludeDelegateResourcesInBodyAsync()
{
// Arrange
var skill = new AgentInlineSkill("my-skill", "A valid skill.", "Instructions.");
@@ -173,9 +172,8 @@ public sealed class AgentInlineSkillTests
// Act
var content = await skill.GetContentAsync();
- // Assert
- Assert.Contains("", content);
- Assert.Contains("dynamic", content);
+ // Assert — resources are no longer rendered in the body
+ Assert.DoesNotContain("", content);
}
[Fact]
@@ -189,7 +187,7 @@ public sealed class AgentInlineSkillTests
var content = await skill.GetContentAsync();
// Assert
- Assert.Contains("", content);
+ Assert.Contains("", content);
Assert.Contains("run", content);
}
@@ -209,7 +207,7 @@ public sealed class AgentInlineSkillTests
}
[Fact]
- public async Task Content_IncludesResourcesAndScriptsAddedBeforeFirstAccessAsync()
+ public async Task Content_IncludesScriptSchemasAddedBeforeFirstAccessAsync()
{
// Arrange
var skill = new AgentInlineSkill("my-skill", "A valid skill.", "Instructions.");
@@ -220,9 +218,8 @@ public sealed class AgentInlineSkillTests
var content = await skill.GetContentAsync();
// Assert
- Assert.Contains("", content);
- Assert.Contains("r1", content);
- Assert.Contains("", content);
+ Assert.DoesNotContain("", content);
+ Assert.Contains("", content);
Assert.Contains("s1", content);
}
@@ -236,8 +233,9 @@ public sealed class AgentInlineSkillTests
// Act
var content = await skill.GetContentAsync();
- // Assert — JSON schema should be present and XML content chars escaped
- Assert.Contains("parameters_schema", content);
+ // Assert — JSON schema should be present inside element (no extra wrapper) with preserved quotes
+ Assert.Contains("", content);
+ Assert.Contains("\"query\"", content);
Assert.DoesNotContain("", content);
- Assert.DoesNotContain("", content);
+ Assert.DoesNotContain("", content);
}
[Fact]
@@ -463,7 +461,7 @@ public sealed class AgentInlineSkillTests
}
[Fact]
- public async Task Content_ScriptWithDescription_IncludesDescriptionAttributeAsync()
+ public async Task Content_ScriptWithDescription_DoesNotEmitDescriptionAttributeAsync()
{
// Arrange
var skill = new AgentInlineSkill("my-skill", "A valid skill.", "Instructions.");
@@ -472,8 +470,10 @@ public sealed class AgentInlineSkillTests
// Act
var content = await skill.GetContentAsync();
- // Assert
- Assert.Contains("description=\"Runs something.\"", content);
+ // Assert — description is no longer emitted in the script_schemas block;
+ // the block only contains parameter schemas for calling scripts.
+ Assert.Contains("", content);
+ Assert.DoesNotContain("with-desc", content);
+ Assert.DoesNotContain("no-desc", content);
}
[Fact]