Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
673f3d9
.NET: Add a TODO AIContextProvider (#5233)
westey-m Apr 14, 2026
b4c853e
.NET: Add a ModeProvider for managing agent modes (#5247)
westey-m Apr 15, 2026
9d89353
.NET: Add sample to show how to build a harness (#5268)
westey-m Apr 15, 2026
d0ac1d8
.NET: Add context window size compaction strategy for harness (#5304)
westey-m Apr 16, 2026
99627e4
Merge branch 'main' into feature-harness
westey-m Apr 16, 2026
8dca006
.NET: Add a file memory provider (#5315)
westey-m Apr 20, 2026
7f661e8
.NET: Harness: Improve prompts and add FileSystem store (#5365)
westey-m Apr 21, 2026
53274fd
.NET: Harness: Improve path validation (#5404)
westey-m Apr 22, 2026
025655b
Merge branch 'main' into feature-harness
westey-m Apr 22, 2026
e4595be
.NET: Add always approve helpers, improve sample and fix bug (#5451)
westey-m Apr 24, 2026
9004282
Merge branch 'main' into feature-harness
westey-m Apr 24, 2026
08aeb67
Merge branch 'main' into feature-harness
westey-m Apr 27, 2026
f747d8a
.NET: Make Todo, Mode and FileMemory providers more configurable (#5477)
westey-m Apr 27, 2026
899394a
.NET: Add subagents provider and sample (#5518)
westey-m Apr 28, 2026
e3f7661
.NET: Harness filememory index plus instructions consistency (#5540)
westey-m Apr 29, 2026
97228e4
.NET: Refactor harness console to be more extensible and easy to unde…
westey-m Apr 30, 2026
a9dafd5
Merge branch 'main' into feature-harness
westey-m Apr 30, 2026
0295b4c
.NET: Add FileAccessProvdider and concurrency fix for FileMemoryProvi…
westey-m Apr 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions dotnet/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
<PackageVersion Include="Microsoft.Extensions.Configuration.UserSecrets" Version="10.0.1" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.1" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.6" />
<PackageVersion Include="Microsoft.Extensions.FileSystemGlobbing" Version="10.0.6" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="10.0.1" />
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.1" />
Expand Down Expand Up @@ -135,6 +136,8 @@
<PackageVersion Include="Microsoft.Azure.Functions.Worker.Sdk" Version="2.0.7" />
<!-- Redis -->
<PackageVersion Include="StackExchange.Redis" Version="2.10.1" />
<!-- Console UX -->
<PackageVersion Include="Spectre.Console" Version="0.49.1" />
<!-- Test -->
<PackageVersion Include="FluentAssertions" Version="8.8.0" />
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Condition="'$(TargetFramework)' == 'net8.0'" Version="8.0.22" />
Expand Down
7 changes: 7 additions & 0 deletions dotnet/agent-framework-dotnet.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,13 @@
<Project Path="samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/Agent_Step04_MixedSkills.csproj" />
<Project Path="samples/02-agents/AgentSkills/Agent_Step05_SkillsWithDI/Agent_Step05_SkillsWithDI.csproj" />
</Folder>
<Folder Name="/Samples/02-agents/Harness/">
<File Path="samples/02-agents/Harness/README.md" />
<Project Path="samples/02-agents/Harness/Harness_Shared_Console/Harness_Shared_Console.csproj" />
<Project Path="samples/02-agents/Harness/Harness_Step01_Research/Harness_Step01_Research.csproj" />
<Project Path="samples/02-agents/Harness/Harness_Step02_Research_WithSubAgents/Harness_Step02_Research_WithSubAgents.csproj" />
<Project Path="samples/02-agents/Harness/Harness_Step03_DataProcessing/Harness_Step03_DataProcessing.csproj" />
</Folder>
<Folder Name="/Samples/02-agents/AGUI/Step05_StateManagement/">
<Project Path="samples/02-agents/AGUI/Step05_StateManagement/Client/Client.csproj" />
<Project Path="samples/02-agents/AGUI/Step05_StateManagement/Server/Server.csproj" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) Microsoft. All rights reserved.

using Microsoft.Agents.AI;

namespace Harness.Shared.Console.Commands;

/// <summary>
/// Handles a console command (e.g., /todos, /mode). Command handlers are checked
/// in order before user input is sent to the agent. The first handler that
/// accepts the input prevents further handlers from being checked.
/// </summary>
public interface ICommandHandler
{
/// <summary>
/// Gets the help text for this command, displayed in the console header.
/// Returns <see langword="null"/> if the command is not currently available.
/// </summary>
/// <returns>Help text like <c>"/todos (show todo list)"</c>, or <see langword="null"/>.</returns>
string? GetHelpText();

/// <summary>
/// Attempts to handle the given user input.
/// </summary>
/// <param name="input">The raw user input string.</param>
/// <param name="session">The current agent session.</param>
/// <returns><see langword="true"/> if this handler handled the input; <see langword="false"/> otherwise.</returns>
bool TryHandle(string input, AgentSession session);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright (c) Microsoft. All rights reserved.

using Microsoft.Agents.AI;

namespace Harness.Shared.Console.Commands;

/// <summary>
/// Handles the <c>/mode</c> command to display or switch the current agent mode.
/// </summary>
internal sealed class ModeCommandHandler : ICommandHandler
{
private readonly AgentModeProvider? _modeProvider;
private readonly IReadOnlyDictionary<string, ConsoleColor>? _modeColors;

/// <summary>
/// Initializes a new instance of the <see cref="ModeCommandHandler"/> class.
/// </summary>
/// <param name="modeProvider">The mode provider, or <see langword="null"/> if not available.</param>
/// <param name="modeColors">Optional mapping of mode names to console colors.</param>
public ModeCommandHandler(AgentModeProvider? modeProvider, IReadOnlyDictionary<string, ConsoleColor>? modeColors = null)
{
this._modeProvider = modeProvider;
this._modeColors = modeColors;
}

/// <inheritdoc/>
public string? GetHelpText() => this._modeProvider is not null ? "/mode [plan|execute] (show or switch mode)" : null;

/// <inheritdoc/>
public bool TryHandle(string input, AgentSession session)
{
if (!input.StartsWith("/mode ", StringComparison.OrdinalIgnoreCase) && !input.Equals("/mode", StringComparison.OrdinalIgnoreCase))
{
return false;
}

if (this._modeProvider is null)
{
System.Console.WriteLine("AgentModeProvider is not available.");
return true;
}

string[] parts = input.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
if (parts.Length < 2)
{
string current = this._modeProvider.GetMode(session);
System.Console.WriteLine($"\n Current mode: {current}\n");
return true;
}

string newMode = parts[1];

try
{
this._modeProvider.SetMode(session, newMode);
System.Console.ForegroundColor = ConsoleWriter.GetModeColor(newMode, this._modeColors);
System.Console.WriteLine($"\n Switched to {newMode} mode.\n");
System.Console.ResetColor();
}
catch (ArgumentException ex)
{
System.Console.ForegroundColor = ConsoleColor.Red;
System.Console.WriteLine($"\n {ex}\n");
System.Console.ResetColor();
}

return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (c) Microsoft. All rights reserved.

using Microsoft.Agents.AI;

namespace Harness.Shared.Console.Commands;

/// <summary>
/// Handles the <c>/todos</c> command to display the current todo list.
/// </summary>
internal sealed class TodoCommandHandler : ICommandHandler
{
private readonly TodoProvider? _todoProvider;

/// <summary>
/// Initializes a new instance of the <see cref="TodoCommandHandler"/> class.
/// </summary>
/// <param name="todoProvider">The todo provider, or <see langword="null"/> if not available.</param>
public TodoCommandHandler(TodoProvider? todoProvider)
{
this._todoProvider = todoProvider;
}

/// <inheritdoc/>
public string? GetHelpText() => this._todoProvider is not null ? "/todos (show todo list)" : null;

/// <inheritdoc/>
public bool TryHandle(string input, AgentSession session)
{
if (!input.Equals("/todos", StringComparison.OrdinalIgnoreCase))
{
return false;
}

if (this._todoProvider is null)
{
System.Console.WriteLine("TodoProvider is not available.");
return true;
}

var todos = this._todoProvider.GetAllTodos(session);
if (todos.Count == 0)
{
System.Console.WriteLine("\n No todos yet.\n");
return true;
}

System.Console.WriteLine();
System.Console.WriteLine(" ── Todo List ──");
foreach (var item in todos)
{
string status = item.IsComplete ? "✓" : "○";
System.Console.ForegroundColor = item.IsComplete ? ConsoleColor.DarkGray : ConsoleColor.White;
System.Console.Write($" [{status}] #{item.Id} {item.Title}");
if (!string.IsNullOrWhiteSpace(item.Description))
{
System.Console.Write($" — {item.Description}");
}

System.Console.WriteLine();
}

System.Console.ResetColor();
System.Console.WriteLine();
return true;
}
}
Loading
Loading