.Net: Add agentic tool registration guide to SK -> AF migration. (#13464)

### Motivation and Context

Addresses a gap in the SK → Agent Framework migration guide for
scenarios where tools are added to the kernel after it's already built
via `kernel.Plugins.Add()`. Referenced from
[microsoft/agent-framework#3276](https://github.com/microsoft/agent-framework/issues/3276#issuecomment-3777591036).

### Description

Adds a "Runtime Tool Registration Transformation" section to
`SemanticKernelToAgentFramework.md` showing the middleware pattern for
dynamic tool registration.

**Semantic Kernel pattern:**
```csharp
Kernel kernel = kernelBuilder.Build();
ChatCompletionAgent agent = new() { Kernel = kernel };

// Later: add tools post-creation
KernelFunction function = KernelFunctionFactory.CreateFromMethod(GetWeather);
KernelPlugin plugin = KernelPluginFactory.CreateFromFunctions("WeatherPlugin", [function]);
kernel.Plugins.Add(plugin);
```

**Agent Framework equivalent:**
```csharp
var augmentedAgent = existingAgent.AsBuilder()
    .Use(async (chatMessages, agentThread, agentRunOptions, next, cancellationToken) =>
    {
        if (agentRunOptions is ChatClientAgentRunOptions opts)
        {
            opts.ChatOptions ??= new ChatOptions();
            opts.ChatOptions.Tools ??= [];
            opts.ChatOptions.Tools.Add(AIFunctionFactory.Create(GetWeather));
        }
        return await next(chatMessages, agentThread, agentRunOptions, cancellationToken);
    })
    .Build();
```

This middleware approach creates a dedicated augmented agent instance
without disrupting existing usages.

### Contribution Checklist

- [x] The code builds clean without any errors or warnings
- [x] The PR follows the [SK Contribution
Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md)
and the [pre-submission formatting
script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts)
raises no violations
- [x] All unit tests pass, and I have added new tests where possible
- [x] I didn't break anyone 😄

<!-- START COPILOT ORIGINAL PROMPT -->



<details>

<summary>Original prompt</summary>

> On SemanticKernelToAgentFramework.md, I got this valuable issue and I
think worth adding a small piece of example in the migration when any
tool is being added to the agent/kernel via instance level, providing
the path suggested in the issue as a solution, mainly the option 1
provided by rogerbarreto.
> 
> https://github.com/microsoft/agent-framework/issues/3276


</details>



<!-- START COPILOT CODING AGENT TIPS -->
---

💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: rogerbarreto <[email protected]>
This commit is contained in:
Copilot
2026-01-23 15:18:39 +00:00
committed by GitHub
co-authored by rogerbarreto
parent 1fe41e17a9
commit 4e055e8fdf
@@ -384,6 +384,73 @@ AIAgent agent = chatClient.CreateAIAgent(
7. Pass tools directly to agent creation method
</configuration_changes>
### Runtime Tool Registration Transformation
<configuration_changes>
In Semantic Kernel, plugins/tools could be added to the kernel after it was already built using `kernel.Plugins.Add()`. Agent Framework provides a similar capability using the builder middleware API.
**Replace this Semantic Kernel post-creation tool registration pattern:**
```csharp
// Define the tool function
[Description("Get the weather for a location")]
static string GetWeather(string location) => $"Weather in {location}";
// Semantic Kernel - Tools added after kernel is already built
Kernel kernel = kernelBuilder.Build();
ChatCompletionAgent agent = new() { Kernel = kernel };
// Later: Add tools to the existing kernel instance
KernelFunction function = KernelFunctionFactory.CreateFromMethod(GetWeather);
KernelPlugin plugin = KernelPluginFactory.CreateFromFunctions("WeatherPlugin", [function]);
kernel.Plugins.Add(plugin);
// Tools are now available on subsequent invocations
await foreach (var item in agent.InvokeAsync(userInput, thread)) { ... }
```
**With this Agent Framework pattern using builder middleware:**
```csharp
// Define the tool function
[Description("Get the weather for a location")]
static string GetWeather(string location) => $"Weather in {location}";
// Start with an existing agent
AIAgent existingAgent = chatClient.CreateAIAgent(
instructions: "You are a helpful assistant");
// Create an augmented agent with additional tools using builder middleware
var augmentedAgent = existingAgent.AsBuilder()
.Use(async (chatMessages, agentThread, agentRunOptions, next, cancellationToken) =>
{
if (agentRunOptions is ChatClientAgentRunOptions chatClientAgentRunOptions)
{
chatClientAgentRunOptions.ChatOptions ??= new ChatOptions();
chatClientAgentRunOptions.ChatOptions.Tools ??= [];
chatClientAgentRunOptions.ChatOptions.Tools.Add(AIFunctionFactory.Create(GetWeather));
}
return await next(chatMessages, agentThread, agentRunOptions, cancellationToken);
})
.Build();
// Use the augmented agent with the additional tools
AgentRunResponse result = await augmentedAgent.RunAsync(userInput, thread);
```
**Required changes:**
1. Call `AsBuilder()` on the existing agent to get a builder
2. Use the `Use()` middleware method to intercept and modify run options
3. Add tools to `ChatClientAgentRunOptions.ChatOptions.Tools` in the middleware
4. Call `Build()` to create the augmented agent instance
5. Use the new augmented agent for invocations that need the additional tools
**Note:** This pattern is the preferred approach as it provides:
- A controlled environment with a dedicated agent instance
- No disruption to existing agent usages
- Dynamic tool composition per user, tenant, or feature flags
- Modular system composition without recreating agents
</configuration_changes>
### Invocation Method Transformation
<api_changes>