Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions Agentic Patterns.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<Project Path="AgenticPatterns.Tests/AgenticPatterns.Tests.csproj" />
<Project Path="AgenticRAG.AgentFramework/AgenticRAG.AgentFramework.csproj" />
<Project Path="AgentRegistry.AgentFramework/AgentRegistry.AgentFramework.csproj" />
<Project Path="AuthenticatedDelegation.AgentFramework/AuthenticatedDelegation.AgentFramework.csproj" />
<Project Path="BoundedExecution.AgentFramework/BoundedExecution.AgentFramework.csproj" />
<Project Path="CacheAwareContext.AgentFramework/CacheAwareContext.AgentFramework.csproj" />
<Project Path="ChainOfVerification.AgentFramework/ChainOfVerification.AgentFramework.csproj" />
Expand Down Expand Up @@ -50,6 +51,7 @@
<Project Path="SemanticCaching.AgentFramework/SemanticCaching.AgentFramework.csproj" />
<Project Path="ConfidenceReporting.AgentFramework/ConfidenceReporting.AgentFramework.csproj" />
<Project Path="ConfidenceReporting.SemanticKernel/ConfidenceReporting.SemanticKernel.csproj" />
<Project Path="ComputerUse.AgentFramework/ComputerUse.AgentFramework.csproj" />
<Project Path="EvaluationAndMonitoring.AgentFramework/EvaluationAndMonitoring.AgentFramework.csproj" />
<Project Path="EvaluationAndMonitoring.SemanticKernel/EvaluationAndMonitoring.SemanticKernel.csproj" />
<Project Path="ExceptionHandlingAndRecovery.AgentFramework/ExceptionHandlingAndRecovery.AgentFramework.csproj" />
Expand Down Expand Up @@ -86,6 +88,7 @@
<Project Path="Planning.SemanticKernel/Planning.SemanticKernel.csproj" />
<Project Path="Prioritization.AgentFramework/Prioritization.AgentFramework.csproj" />
<Project Path="Prioritization.SemanticKernel/Prioritization.SemanticKernel.csproj" />
<Project Path="ProgressiveAgentRollout.AgentFramework/ProgressiveAgentRollout.AgentFramework.csproj" />
<Project Path="ProgressiveToolDisclosure.AgentFramework/ProgressiveToolDisclosure.AgentFramework.csproj" />
<Project Path="PromptChaining.AgentFramework/PromptChaining.AgentFramework.csproj" />
<Project Path="PromptChaining.SemanticKernel/PromptChaining.SemanticKernel.csproj" />
Expand All @@ -94,14 +97,17 @@
<Project Path="RalphLoop.AgentFramework/RalphLoop.AgentFramework.csproj" />
<Project Path="ResourceAwareOptimization.AgentFramework/ResourceAwareOptimization.AgentFramework.csproj" />
<Project Path="ResourceAwareOptimization.SemanticKernel/ResourceAwareOptimization.SemanticKernel.csproj" />
<Project Path="ReversibleActionCompensation.AgentFramework/ReversibleActionCompensation.AgentFramework.csproj" />
<Project Path="Routing.AgentFramework.Workflow/Routing.AgentFramework.Workflow.csproj" />
<Project Path="Routing.AgentFramework/Routing.AgentFramework.csproj" />
<Project Path="Routing.SemanticKernel/Routing.SemanticKernel.csproj" />
<Project Path="SelfNote.AgentFramework/SelfNote.AgentFramework.csproj" />
<Project Path="SelfNote.SemanticKernel/SelfNote.SemanticKernel.csproj" />
<Project Path="SelfHealingOperationsLoop.AgentFramework/SelfHealingOperationsLoop.AgentFramework.csproj" />
<Project Path="Shared/Shared.csproj" />
<Project Path="SkillLearning.AgentFramework/SkillLearning.AgentFramework.csproj" />
<Project Path="StigmergicCoordination.AgentFramework/StigmergicCoordination.AgentFramework.csproj" />
<Project Path="SyntheticUserSimulation.AgentFramework/SyntheticUserSimulation.AgentFramework.csproj" />
<Project Path="ToolUse.AgentFramework/ToolUse.AgentFramework.csproj" />
<Project Path="ToolUse.SemanticKernel/ToolUse.SemanticKernel.csproj" />
<Project Path="ToolAuthorization.AgentFramework/ToolAuthorization.AgentFramework.csproj" />
Expand Down
6 changes: 6 additions & 0 deletions AgenticPatterns.Tests/AgenticPatterns.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@

<ItemGroup>
<ProjectReference Include="..\AgentCommunicationFaultTolerance.AgentFramework\AgentCommunicationFaultTolerance.AgentFramework.csproj"/>
<ProjectReference Include="..\AuthenticatedDelegation.AgentFramework\AuthenticatedDelegation.AgentFramework.csproj"/>
<ProjectReference Include="..\ComputerUse.AgentFramework\ComputerUse.AgentFramework.csproj"/>
<ProjectReference Include="..\ProgressiveAgentRollout.AgentFramework\ProgressiveAgentRollout.AgentFramework.csproj"/>
<ProjectReference Include="..\ReversibleActionCompensation.AgentFramework\ReversibleActionCompensation.AgentFramework.csproj"/>
<ProjectReference Include="..\SelfHealingOperationsLoop.AgentFramework\SelfHealingOperationsLoop.AgentFramework.csproj"/>
<ProjectReference Include="..\SyntheticUserSimulation.AgentFramework\SyntheticUserSimulation.AgentFramework.csproj"/>
<ProjectReference Include="..\AgentRegistry.AgentFramework\AgentRegistry.AgentFramework.csproj"/>
<ProjectReference Include="..\ChainOfVerification.AgentFramework\ChainOfVerification.AgentFramework.csproj"/>
<ProjectReference Include="..\ContextAssembly.AgentFramework\ContextAssembly.AgentFramework.csproj"/>
Expand Down
231 changes: 231 additions & 0 deletions AgenticPatterns.Tests/HighestPriorityPatternTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
using AuthenticatedDelegation.AgentFramework;
using ComputerUse.AgentFramework;
using ProgressiveAgentRollout.AgentFramework;
using ReversibleActionCompensation.AgentFramework;
using SelfHealingOperationsLoop.AgentFramework;
using SyntheticUserSimulation.AgentFramework;
using Xunit;

namespace AgenticPatterns.Tests;

public class ReversibleActionCompensationTests
{
[Fact]
public void FailureCompensatesCompletedStepsInReverseOrder()
{
var effects = new List<string>();
CompensableStep Step(string name) => new(name, _ => effects.Add($"apply-{name}"), _ => effects.Add($"undo-{name}"));
CompensableStep[] steps = [Step("a"), Step("b"), new("c", _ => throw new InvalidOperationException("failed"), _ => { })];

var result = new SagaRunner().Run("saga-1", steps);

Assert.Equal(SagaStatus.Compensated, result.Status);
Assert.Equal(["apply-a", "apply-b", "undo-b", "undo-a"], effects);
}

[Fact]
public void ReplayingASagaDoesNotRepeatEffects()
{
var calls = 0;
CompensableStep[] steps = [new("once", _ => calls++, _ => calls--)];
var runner = new SagaRunner();

var first = runner.Run("same-id", steps);
var replay = runner.Run("same-id", steps);

Assert.Same(first, replay);
Assert.Equal(1, calls);
}
}

public class ProgressiveAgentRolloutTests
{
[Fact]
public void ShadowRunsTheCandidateWithoutServingIt()
{
var route = new RolloutController(new(2, 0.1, 0.1)).Route("request");

Assert.True(route.RunCandidate);
Assert.False(route.ServeCandidate);
}

[Fact]
public void HealthyWindowsPromoteAndARegressionRollsBack()
{
var rollout = new RolloutController(new(2, 0.05, 0.1));
for (var stage = 0; stage < 3; stage++)
{
rollout.Observe(new(0.8, 0.9));
rollout.Observe(new(0.8, 0.9));
}

Assert.Equal(RolloutStage.Full, rollout.Stage);

rollout.Observe(new(0.8, 0.4, true));
rollout.Observe(new(0.8, 0.4));

Assert.Equal(RolloutStage.RolledBack, rollout.Stage);
Assert.Equal(new(false, false), rollout.Route("request"));
}

[Fact]
public void NonFiniteMetricsAreRejected() =>
Assert.Throws<ArgumentOutOfRangeException>(() =>
new RolloutController(new(2, 0.05, 0.1)).Observe(new(double.NaN, 0.8)));
}

public class SyntheticUserSimulationTests
{
[Fact]
public async Task SimulatorReactsToThePriorTurnAndCanStop()
{
var observedHistory = -1;
var result = await new SimulationHarness().RunAsync(
new("customer", "get help", "impatient"),
(history, _) =>
{
observedHistory = history.Count;
return Task.FromResult(history.Count == 0 ? new UserMove("help") : new UserMove("done", Stop: true));
},
(message, _) => Task.FromResult($"answer to {message}"),
maxTurns: 3);

Assert.Single(result.Turns);
Assert.Equal(1, observedHistory);
Assert.False(result.ReachedTurnLimit);
}

[Fact]
public async Task HostTurnLimitStopsAnEndlessPersona()
{
var result = await new SimulationHarness().RunAsync(
new("customer", "keep talking", "persistent"),
(_, _) => Task.FromResult(new UserMove("again")),
(_, _) => Task.FromResult("reply"),
maxTurns: 2);

Assert.True(result.ReachedTurnLimit);
Assert.Equal(2, result.Turns.Count);
}
}

public class ComputerUseTests
{
[Fact]
public void HiddenControlsCannotBeClickedThroughAPopup()
{
var desktop = new VirtualDesktop();

var result = desktop.Apply(new("click", 10, 5));

Assert.False(result.Applied);
Assert.True(desktop.PopupOpen);
}

[Fact]
public async Task ScreenshotActionObservationLoopReachesTheGoal()
{
var result = await new ComputerUseRunner().RunAsync(
new VirtualDesktop(),
(screen, _) =>
{
var target = screen.Elements[0];
return Task.FromResult(new GuiAction("click", target.X, target.Y));
},
screen => screen.DarkMode,
maxSteps: 3);

Assert.True(result.Completed);
Assert.Equal(3, result.Steps.Count);
Assert.All(result.Steps, step => Assert.True(step.Applied));
}
}

public class AuthenticatedDelegationTests
{
private static readonly byte[] Key = [.. Enumerable.Repeat((byte)7, 32)];
private static readonly DateTimeOffset Now = new(2026, 9, 4, 12, 0, 0, TimeSpan.Zero);

private static (DelegatedResourceServer Server, DelegationGrant Grant) Setup()
{
var authority = new DelegationAuthority(Key);
var grant = authority.Issue(new("g1", "user", "agent", "payments", ["pay"], "invoice-1", 100m,
Now.AddMinutes(-1), Now.AddMinutes(5)));
return (new(authority, "payments"), grant);
}

[Fact]
public void ScopedRequestIsAuthorizedAndAttributed()
{
var (server, grant) = Setup();
var decision = server.Authorize(new("r1", "agent", "payments", "pay", "invoice-1", 75m, grant), Now);

Assert.True(decision.Allowed);
Assert.Collection(server.AuditLog, entry =>
{
Assert.Equal("user", entry.User);
Assert.Equal("agent", entry.Agent);
Assert.True(entry.Allowed);
});
}

[Fact]
public void TamperingAndExcessAuthorityAreRejected()
{
var (server, grant) = Setup();

Assert.False(server.Authorize(new("r1", "agent", "payments", "pay", "invoice-2", 75m, grant), Now).Allowed);
Assert.False(server.Authorize(new("r2", "agent", "payments", "pay", "invoice-1", 101m, grant), Now).Allowed);
Assert.False(server.Authorize(new("r3", "agent", "payments", "pay", "invoice-1", 75m,
grant with { MaxAmount = 1000m }), Now).Allowed);
Assert.Equal(3, server.AuditLog.Count);
}
}

public class SelfHealingOperationsLoopTests
{
private static readonly HealingPolicy Policy = new(
450, 0.02, new HashSet<string>(StringComparer.Ordinal) { "rollback" }, 0.8);
private static readonly ServiceHealth Unhealthy = new("v2", 1900, 0.14, "after v2 deploy");

[Fact]
public void OutOfPolicyRemediationEscalatesWithoutExecuting()
{
var executed = false;
var result = new SelfHealingLoop(Policy).Run(Unhealthy, new("run_migration", 0.99, "guess"), _ =>
{
executed = true;
return Unhealthy;
});

Assert.Equal(HealingStatus.Escalated, result.Status);
Assert.False(executed);
}

[Fact]
public void ApprovedRemediationMustVerifyRecovery()
{
var loop = new SelfHealingLoop(Policy);

var recovered = loop.Run(Unhealthy, new("rollback", 0.95, "bad deploy"),
_ => new("v1", 300, 0.005, "baseline"));
var stillBroken = loop.Run(Unhealthy, new("rollback", 0.95, "bad deploy"), _ => Unhealthy);

Assert.Equal(HealingStatus.Resolved, recovered.Status);
Assert.Equal(HealingStatus.Escalated, stillBroken.Status);
}

[Fact]
public void NonFiniteConfidenceCannotAuthorizeAnAction()
{
var executed = false;
var result = new SelfHealingLoop(Policy).Run(Unhealthy, new("rollback", double.NaN, "invalid"), _ =>
{
executed = true;
return Unhealthy;
});

Assert.Equal(HealingStatus.Escalated, result.Status);
Assert.False(executed);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
</PropertyGroup>

</Project>
Loading