Skip to content

Commit c727be2

Browse files
westey-mCopilotrogerbarreto
authored
.NET: Harness Feature branch (#5310)
* .NET: Add a TODO AIContextProvider (#5233) * Add a TODO AIContextProvider * Add unit tests * Address PR comments * Address PR comments * Fix test after removing one tool * .NET: Add a ModeProvider for managing agent modes (#5247) * Add a ModeProvider for managing agent modes * Fix typo * Fix typo * Fix typo * Address PR comments * .NET: Add sample to show how to build a harness (#5268) * Add sample to show how to build a harness * Improve sample * Sample max output tokens and model * Fix encoding * Fix model name in readme * Address PR comments * .NET: Add context window size compaction strategy for harness (#5304) * Add context window size compaction strategy for harness * Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Address PR comments --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * .NET: Add a file memory provider (#5315) * Add a file memory provider * Address PR comments * Fix review comments. * Add additional unit tests * Addressing PR comments. * .NET: Harness: Improve prompts and add FileSystem store (#5365) * Harness: Improve prompts and add FileSystem store * Address PR comments * .NET: Harness: Improve path validation (#5404) * Harness: Improve path validation * Address PR comments * .NET: Add always approve helpers, improve sample and fix bug (#5451) * Add always approve helpers, improve sample and fix bug * Address PR comments * .NET: Make Todo, Mode and FileMemory providers more configurable (#5477) * Make Todo, Mode and FileMemory providers more configurable * Address PR comments. * .NET: Add subagents provider and sample (#5518) * Add subagents provider and sample * Addressing PR comments. * .NET: Harness filememory index plus instructions consistency (#5540) * Add FileMemoryProvider index and improve instruction consistency * Address PR comments. * Address PR comments * Address PR comments. * Apply suggestion from @rogerbarreto Co-authored-by: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com> --------- Co-authored-by: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com> * .NET: Refactor harness console to be more extensible and easy to understand with better UX (#5573) * Refactor harness console to be more extensible and easy to understand with better UX. * Fix formatting issues. * Allow multiple clarifications in one response * Address PR comments * .NET: Add FileAccessProvdider and concurrency fix for FileMemoryProvider (#5583) * Add FileAccessProvdider and concurrency fix for FileMemoryProvider * Address PR comments --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com>
1 parent 540193c commit c727be2

83 files changed

Lines changed: 13540 additions & 1 deletion

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

dotnet/Directory.Packages.props

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
<PackageVersion Include="Microsoft.Extensions.Configuration.UserSecrets" Version="10.0.1" />
8787
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.1" />
8888
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.6" />
89+
<PackageVersion Include="Microsoft.Extensions.FileSystemGlobbing" Version="10.0.6" />
8990
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="10.0.1" />
9091
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="10.0.0" />
9192
<PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.1" />
@@ -135,6 +136,8 @@
135136
<PackageVersion Include="Microsoft.Azure.Functions.Worker.Sdk" Version="2.0.7" />
136137
<!-- Redis -->
137138
<PackageVersion Include="StackExchange.Redis" Version="2.10.1" />
139+
<!-- Console UX -->
140+
<PackageVersion Include="Spectre.Console" Version="0.49.1" />
138141
<!-- Test -->
139142
<PackageVersion Include="FluentAssertions" Version="8.8.0" />
140143
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Condition="'$(TargetFramework)' == 'net8.0'" Version="8.0.22" />

dotnet/agent-framework-dotnet.slnx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,13 @@
117117
<Project Path="samples/02-agents/AgentSkills/Agent_Step04_MixedSkills/Agent_Step04_MixedSkills.csproj" />
118118
<Project Path="samples/02-agents/AgentSkills/Agent_Step05_SkillsWithDI/Agent_Step05_SkillsWithDI.csproj" />
119119
</Folder>
120+
<Folder Name="/Samples/02-agents/Harness/">
121+
<File Path="samples/02-agents/Harness/README.md" />
122+
<Project Path="samples/02-agents/Harness/Harness_Shared_Console/Harness_Shared_Console.csproj" />
123+
<Project Path="samples/02-agents/Harness/Harness_Step01_Research/Harness_Step01_Research.csproj" />
124+
<Project Path="samples/02-agents/Harness/Harness_Step02_Research_WithSubAgents/Harness_Step02_Research_WithSubAgents.csproj" />
125+
<Project Path="samples/02-agents/Harness/Harness_Step03_DataProcessing/Harness_Step03_DataProcessing.csproj" />
126+
</Folder>
120127
<Folder Name="/Samples/02-agents/AGUI/Step05_StateManagement/">
121128
<Project Path="samples/02-agents/AGUI/Step05_StateManagement/Client/Client.csproj" />
122129
<Project Path="samples/02-agents/AGUI/Step05_StateManagement/Server/Server.csproj" />
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
3+
using Microsoft.Agents.AI;
4+
5+
namespace Harness.Shared.Console.Commands;
6+
7+
/// <summary>
8+
/// Handles a console command (e.g., /todos, /mode). Command handlers are checked
9+
/// in order before user input is sent to the agent. The first handler that
10+
/// accepts the input prevents further handlers from being checked.
11+
/// </summary>
12+
public interface ICommandHandler
13+
{
14+
/// <summary>
15+
/// Gets the help text for this command, displayed in the console header.
16+
/// Returns <see langword="null"/> if the command is not currently available.
17+
/// </summary>
18+
/// <returns>Help text like <c>"/todos (show todo list)"</c>, or <see langword="null"/>.</returns>
19+
string? GetHelpText();
20+
21+
/// <summary>
22+
/// Attempts to handle the given user input.
23+
/// </summary>
24+
/// <param name="input">The raw user input string.</param>
25+
/// <param name="session">The current agent session.</param>
26+
/// <returns><see langword="true"/> if this handler handled the input; <see langword="false"/> otherwise.</returns>
27+
bool TryHandle(string input, AgentSession session);
28+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
3+
using Microsoft.Agents.AI;
4+
5+
namespace Harness.Shared.Console.Commands;
6+
7+
/// <summary>
8+
/// Handles the <c>/mode</c> command to display or switch the current agent mode.
9+
/// </summary>
10+
internal sealed class ModeCommandHandler : ICommandHandler
11+
{
12+
private readonly AgentModeProvider? _modeProvider;
13+
private readonly IReadOnlyDictionary<string, ConsoleColor>? _modeColors;
14+
15+
/// <summary>
16+
/// Initializes a new instance of the <see cref="ModeCommandHandler"/> class.
17+
/// </summary>
18+
/// <param name="modeProvider">The mode provider, or <see langword="null"/> if not available.</param>
19+
/// <param name="modeColors">Optional mapping of mode names to console colors.</param>
20+
public ModeCommandHandler(AgentModeProvider? modeProvider, IReadOnlyDictionary<string, ConsoleColor>? modeColors = null)
21+
{
22+
this._modeProvider = modeProvider;
23+
this._modeColors = modeColors;
24+
}
25+
26+
/// <inheritdoc/>
27+
public string? GetHelpText() => this._modeProvider is not null ? "/mode [plan|execute] (show or switch mode)" : null;
28+
29+
/// <inheritdoc/>
30+
public bool TryHandle(string input, AgentSession session)
31+
{
32+
if (!input.StartsWith("/mode ", StringComparison.OrdinalIgnoreCase) && !input.Equals("/mode", StringComparison.OrdinalIgnoreCase))
33+
{
34+
return false;
35+
}
36+
37+
if (this._modeProvider is null)
38+
{
39+
System.Console.WriteLine("AgentModeProvider is not available.");
40+
return true;
41+
}
42+
43+
string[] parts = input.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
44+
if (parts.Length < 2)
45+
{
46+
string current = this._modeProvider.GetMode(session);
47+
System.Console.WriteLine($"\n Current mode: {current}\n");
48+
return true;
49+
}
50+
51+
string newMode = parts[1];
52+
53+
try
54+
{
55+
this._modeProvider.SetMode(session, newMode);
56+
System.Console.ForegroundColor = ConsoleWriter.GetModeColor(newMode, this._modeColors);
57+
System.Console.WriteLine($"\n Switched to {newMode} mode.\n");
58+
System.Console.ResetColor();
59+
}
60+
catch (ArgumentException ex)
61+
{
62+
System.Console.ForegroundColor = ConsoleColor.Red;
63+
System.Console.WriteLine($"\n {ex}\n");
64+
System.Console.ResetColor();
65+
}
66+
67+
return true;
68+
}
69+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
3+
using Microsoft.Agents.AI;
4+
5+
namespace Harness.Shared.Console.Commands;
6+
7+
/// <summary>
8+
/// Handles the <c>/todos</c> command to display the current todo list.
9+
/// </summary>
10+
internal sealed class TodoCommandHandler : ICommandHandler
11+
{
12+
private readonly TodoProvider? _todoProvider;
13+
14+
/// <summary>
15+
/// Initializes a new instance of the <see cref="TodoCommandHandler"/> class.
16+
/// </summary>
17+
/// <param name="todoProvider">The todo provider, or <see langword="null"/> if not available.</param>
18+
public TodoCommandHandler(TodoProvider? todoProvider)
19+
{
20+
this._todoProvider = todoProvider;
21+
}
22+
23+
/// <inheritdoc/>
24+
public string? GetHelpText() => this._todoProvider is not null ? "/todos (show todo list)" : null;
25+
26+
/// <inheritdoc/>
27+
public bool TryHandle(string input, AgentSession session)
28+
{
29+
if (!input.Equals("/todos", StringComparison.OrdinalIgnoreCase))
30+
{
31+
return false;
32+
}
33+
34+
if (this._todoProvider is null)
35+
{
36+
System.Console.WriteLine("TodoProvider is not available.");
37+
return true;
38+
}
39+
40+
var todos = this._todoProvider.GetAllTodos(session);
41+
if (todos.Count == 0)
42+
{
43+
System.Console.WriteLine("\n No todos yet.\n");
44+
return true;
45+
}
46+
47+
System.Console.WriteLine();
48+
System.Console.WriteLine(" ── Todo List ──");
49+
foreach (var item in todos)
50+
{
51+
string status = item.IsComplete ? "✓" : "○";
52+
System.Console.ForegroundColor = item.IsComplete ? ConsoleColor.DarkGray : ConsoleColor.White;
53+
System.Console.Write($" [{status}] #{item.Id} {item.Title}");
54+
if (!string.IsNullOrWhiteSpace(item.Description))
55+
{
56+
System.Console.Write($" — {item.Description}");
57+
}
58+
59+
System.Console.WriteLine();
60+
}
61+
62+
System.Console.ResetColor();
63+
System.Console.WriteLine();
64+
return true;
65+
}
66+
}

0 commit comments

Comments
 (0)