diff --git a/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillsProvider.cs b/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillsProvider.cs
index 6cea629664..1954260598 100644
--- a/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillsProvider.cs
+++ b/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillsProvider.cs
@@ -40,16 +40,6 @@ public sealed partial class AgentSkillsProvider : AIContextProvider
///
private const string SkillsPlaceholder = "{skills}";
- ///
- /// Placeholder token for the script instructions in the prompt template.
- ///
- private const string ScriptInstructionsPlaceholder = "{script_instructions}";
-
- ///
- /// Placeholder token for the resource instructions in the prompt template.
- ///
- private const string ResourceInstructionsPlaceholder = "{resource_instructions}";
-
private const string DefaultSkillsInstructionPrompt =
"""
You have access to skills containing domain-specific knowledge and capabilities.
@@ -62,8 +52,9 @@ You have access to skills containing domain-specific knowledge and capabilities.
When a task aligns with a skill's domain, follow these steps in exact order:
- Use `load_skill` to retrieve the skill's instructions.
- Follow the provided guidance.
- {resource_instructions}
- {script_instructions}
+ - Use `read_skill_resource` to read any referenced resources, using the name exactly as listed
+ (e.g. `"style-guide"` not `"style-guide.md"`, `"references/FAQ.md"` not `"FAQ.md"`).
+ - Use `run_skill_script` to run referenced scripts, using the name exactly as listed.
Only load what is needed, when it is needed.
""";
@@ -258,18 +249,8 @@ private IList BuildTools(IList skills)
sb.AppendLine(" ");
}
- const string ResourceInstruction =
- """
- - Use `read_skill_resource` to read any referenced resources, using the name exactly as listed
- (e.g. `"style-guide"` not `"style-guide.md"`, `"references/FAQ.md"` not `"FAQ.md"`).
- """;
-
- const string ScriptInstruction = "- Use `run_skill_script` to run referenced scripts, using the name exactly as listed.";
-
return new StringBuilder(promptTemplate)
.Replace(SkillsPlaceholder, sb.ToString().TrimEnd())
- .Replace(ResourceInstructionsPlaceholder, ResourceInstruction)
- .Replace(ScriptInstructionsPlaceholder, ScriptInstruction)
.ToString();
}
@@ -378,20 +359,6 @@ private static void ValidatePromptTemplate(string template, string paramName)
$"The custom prompt template must contain the '{SkillsPlaceholder}' placeholder for the generated skills list.",
paramName);
}
-
- if (template.IndexOf(ResourceInstructionsPlaceholder, StringComparison.Ordinal) < 0)
- {
- throw new ArgumentException(
- $"The custom prompt template must contain the '{ResourceInstructionsPlaceholder}' placeholder for resource instructions.",
- paramName);
- }
-
- if (template.IndexOf(ScriptInstructionsPlaceholder, StringComparison.Ordinal) < 0)
- {
- throw new ArgumentException(
- $"The custom prompt template must contain the '{ScriptInstructionsPlaceholder}' placeholder for script instructions.",
- paramName);
- }
}
[LoggerMessage(LogLevel.Information, "Loading skill: {SkillName}")]
diff --git a/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillsProviderBuilder.cs b/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillsProviderBuilder.cs
index e49c620187..9fdde1c701 100644
--- a/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillsProviderBuilder.cs
+++ b/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillsProviderBuilder.cs
@@ -134,9 +134,7 @@ public AgentSkillsProviderBuilder UseSource(AgentSkillsSource source)
///
/// Sets a custom system prompt template.
///
- /// The prompt template with {skills} placeholder for the skills list,
- /// {resource_instructions} for optional resource instructions,
- /// and {script_instructions} for optional script instructions.
+ /// The prompt template with {skills} placeholder for the skills list.
/// This builder instance for chaining.
public AgentSkillsProviderBuilder UsePromptTemplate(string promptTemplate)
{
diff --git a/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillsProviderOptions.cs b/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillsProviderOptions.cs
index 8ef84905c6..8d4578633a 100644
--- a/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillsProviderOptions.cs
+++ b/dotnet/src/Microsoft.Agents.AI/Skills/AgentSkillsProviderOptions.cs
@@ -13,9 +13,7 @@ public sealed class AgentSkillsProviderOptions
{
///
/// Gets or sets a custom system prompt template for advertising skills.
- /// The template must contain {skills} as the placeholder for the generated skills list,
- /// {resource_instructions} for resource instructions,
- /// and {script_instructions} for script instructions.
+ /// The template must contain {skills} as the placeholder for the generated skills list.
/// When , a default template is used.
///
public string? SkillsInstructionPrompt { get; set; }
diff --git a/dotnet/tests/Microsoft.Agents.AI.UnitTests/AgentSkills/AgentSkillsProviderBuilderTests.cs b/dotnet/tests/Microsoft.Agents.AI.UnitTests/AgentSkills/AgentSkillsProviderBuilderTests.cs
index 85335256a7..334c7826ec 100644
--- a/dotnet/tests/Microsoft.Agents.AI.UnitTests/AgentSkills/AgentSkillsProviderBuilderTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.UnitTests/AgentSkills/AgentSkillsProviderBuilderTests.cs
@@ -159,7 +159,7 @@ public void Build_FluentChaining_ReturnsSameBuilder()
var result = builder
.UseSource(source)
.UseScriptApproval(false)
- .UsePromptTemplate("Skills:\n{skills}\n{resource_instructions}\n{script_instructions}");
+ .UsePromptTemplate("Skills:\n{skills}");
// Assert
Assert.Same(builder, result);
diff --git a/dotnet/tests/Microsoft.Agents.AI.UnitTests/AgentSkills/AgentSkillsProviderTests.cs b/dotnet/tests/Microsoft.Agents.AI.UnitTests/AgentSkills/AgentSkillsProviderTests.cs
index 6577bea86c..661b0c77fa 100644
--- a/dotnet/tests/Microsoft.Agents.AI.UnitTests/AgentSkills/AgentSkillsProviderTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.UnitTests/AgentSkills/AgentSkillsProviderTests.cs
@@ -100,7 +100,7 @@ public async Task InvokingCoreAsync_CustomPromptTemplate_UsesCustomTemplateAsync
this.CreateSkill("custom-prompt-skill", "Custom prompt", "Body.");
var options = new AgentSkillsProviderOptions
{
- SkillsInstructionPrompt = "Custom template: {skills}\n{resource_instructions}\n{script_instructions}"
+ SkillsInstructionPrompt = "Custom template: {skills}"
};
var provider = new AgentSkillsProvider(new AgentFileSkillsSource(this._testRoot, s_noOpExecutor), options);
var inputContext = new AIContext();
@@ -122,7 +122,7 @@ public void Constructor_PromptWithoutSkillsPlaceholder_ThrowsArgumentException()
// Arrange
var options = new AgentSkillsProviderOptions
{
- SkillsInstructionPrompt = "No skills placeholder here {resource_instructions} {script_instructions}"
+ SkillsInstructionPrompt = "No skills placeholder here"
};
// Act & Assert
@@ -133,28 +133,12 @@ public void Constructor_PromptWithoutSkillsPlaceholder_ThrowsArgumentException()
}
[Fact]
- public void Constructor_PromptWithoutRunnerInstructionsPlaceholder_ThrowsArgumentException()
+ public void Constructor_PromptWithOnlySkillsPlaceholder_Succeeds()
{
// Arrange
var options = new AgentSkillsProviderOptions
{
- SkillsInstructionPrompt = "Has skills {skills} but no runner instructions {resource_instructions}"
- };
-
- // Act & Assert
- var ex = Assert.Throws(() =>
- new AgentSkillsProvider(new AgentFileSkillsSource(this._testRoot, s_noOpExecutor), options));
- Assert.Contains("{script_instructions}", ex.Message);
- Assert.Equal("options", ex.ParamName);
- }
-
- [Fact]
- public void Constructor_PromptWithBothPlaceholders_Succeeds()
- {
- // Arrange
- var options = new AgentSkillsProviderOptions
- {
- SkillsInstructionPrompt = "Skills: {skills}\nResources: {resource_instructions}\nRunner: {script_instructions}"
+ SkillsInstructionPrompt = "Skills: {skills}"
};
// Act — should not throw
@@ -165,19 +149,25 @@ public void Constructor_PromptWithBothPlaceholders_Succeeds()
}
[Fact]
- public void Constructor_PromptWithoutResourceInstructionsPlaceholder_ThrowsArgumentException()
+ public async Task InvokingCoreAsync_CustomTemplateWithLegacyPlaceholders_RendersThemLiterallyAsync()
{
- // Arrange
+ // Arrange — template contains legacy placeholder tokens that are no longer substituted
+ this.CreateSkill("literal-test-skill", "Literal test", "Body.");
var options = new AgentSkillsProviderOptions
{
- SkillsInstructionPrompt = "Has skills {skills} and runner {script_instructions} but no resource instructions"
+ SkillsInstructionPrompt = "Skills: {skills}\nRes: {resource_instructions}\nScript: {script_instructions}"
};
+ var provider = new AgentSkillsProvider(new AgentFileSkillsSource(this._testRoot, s_noOpExecutor), options);
+ var inputContext = new AIContext();
+ var invokingContext = new AIContextProvider.InvokingContext(this._agent, session: null, inputContext);
- // Act & Assert
- var ex = Assert.Throws(() =>
- new AgentSkillsProvider(new AgentFileSkillsSource(this._testRoot, s_noOpExecutor), options));
- Assert.Contains("{resource_instructions}", ex.Message);
- Assert.Equal("options", ex.ParamName);
+ // Act
+ var result = await provider.InvokingAsync(invokingContext, CancellationToken.None);
+
+ // Assert — legacy tokens render literally, not substituted
+ Assert.NotNull(result.Instructions);
+ Assert.Contains("{resource_instructions}", result.Instructions);
+ Assert.Contains("{script_instructions}", result.Instructions);
}
[Fact]