Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
114 changes: 57 additions & 57 deletions samples/AgenTerra.Sample/ReasoningToolSample.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,111 +16,111 @@ public static async Task RunAsync()
Console.WriteLine("=== Fox, Chicken, and Grain River Crossing Puzzle ===");
Console.WriteLine();

var reasoningTool = new ReasoningTool();
using var reasoningTool = new ReasoningTool();
var sessionId = Guid.NewGuid().ToString();

// Step 1: Think - Initial State Analysis
var response1 = await reasoningTool.ThinkAsync(new ThinkInput(
SessionId: sessionId,
Title: "Initial State Analysis",
Thought: "Man, fox, chicken, grain on left bank. Goal: all on right bank. Boat holds man + one item.",
Action: "Identify constraints",
Confidence: 0.9
sessionId,
"Initial State Analysis",
"Man, fox, chicken, grain on left bank. Goal: all on right bank. Boat holds man + one item.",
"Identify constraints",
0.9
));
Console.WriteLine(response1);

// Step 2: Analyze - Constraint Analysis
var response2 = await reasoningTool.AnalyzeAsync(new AnalyzeInput(
SessionId: sessionId,
Title: "Constraint Analysis",
Result: "Fox eats chicken if alone. Chicken eats grain if alone.",
Analysis: "Must never leave fox+chicken or chicken+grain together without the man present.",
NextAction: NextAction.Continue,
Confidence: 0.95
sessionId,
"Constraint Analysis",
"Fox eats chicken if alone. Chicken eats grain if alone.",
"Must never leave fox+chicken or chicken+grain together without the man present.",
NextAction.Continue,
0.95
));
Console.WriteLine(response2);

// Step 3: Think - First Move Strategy
var response3 = await reasoningTool.ThinkAsync(new ThinkInput(
SessionId: sessionId,
Title: "First Move Strategy",
Thought: "Chicken is the conflict point. If we take fox first, chicken eats grain. If we take grain first, fox eats chicken.",
Action: "Take chicken across first",
Confidence: 0.85
sessionId,
"First Move Strategy",
"Chicken is the conflict point. If we take fox first, chicken eats grain. If we take grain first, fox eats chicken.",
"Take chicken across first",
0.85
));
Console.WriteLine(response3);

// Step 4: Analyze - After First Move
var response4 = await reasoningTool.AnalyzeAsync(new AnalyzeInput(
SessionId: sessionId,
Title: "After First Move",
Result: "Left bank: fox, grain. Right bank: chicken. Boat with man on left.",
Analysis: "Fox and grain safe together. Can now move either fox or grain.",
NextAction: NextAction.Continue,
Confidence: 0.9
sessionId,
"After First Move",
"Left bank: fox, grain. Right bank: chicken. Boat with man on left.",
"Fox and grain safe together. Can now move either fox or grain.",
NextAction.Continue,
0.9
));
Console.WriteLine(response4);

// Step 5: Think - Second Move
var response5 = await reasoningTool.ThinkAsync(new ThinkInput(
SessionId: sessionId,
Title: "Second Move",
Thought: "Take fox across. But if we leave fox with chicken, fox eats chicken.",
Action: "Take fox across, bring chicken back",
Confidence: 0.8
sessionId,
"Second Move",
"Take fox across. But if we leave fox with chicken, fox eats chicken.",
"Take fox across, bring chicken back",
0.8
));
Console.WriteLine(response5);

// Step 6: Analyze - After Second Move
var response6 = await reasoningTool.AnalyzeAsync(new AnalyzeInput(
SessionId: sessionId,
Title: "After Second Move",
Result: "Left bank: chicken, grain. Right bank: fox. Boat with man on left.",
Analysis: "Fox is safe alone. Now need to get grain across without leaving it with chicken.",
NextAction: NextAction.Continue,
Confidence: 0.9
sessionId,
"After Second Move",
"Left bank: chicken, grain. Right bank: fox. Boat with man on left.",
"Fox is safe alone. Now need to get grain across without leaving it with chicken.",
NextAction.Continue,
0.9
));
Console.WriteLine(response6);

// Step 7: Think - Third Move
var response7 = await reasoningTool.ThinkAsync(new ThinkInput(
SessionId: sessionId,
Title: "Third Move",
Thought: "Take grain across, leave fox and grain together (safe).",
Action: "Take grain across",
Confidence: 0.9
sessionId,
"Third Move",
"Take grain across, leave fox and grain together (safe).",
"Take grain across",
0.9
));
Console.WriteLine(response7);

// Step 8: Analyze - After Third Move
var response8 = await reasoningTool.AnalyzeAsync(new AnalyzeInput(
SessionId: sessionId,
Title: "After Third Move",
Result: "Left bank: chicken. Right bank: fox, grain. Boat with man on right.",
Analysis: "Fox and grain are safe together. Only chicken remains on left bank.",
NextAction: NextAction.Continue,
Confidence: 0.95
sessionId,
"After Third Move",
"Left bank: chicken. Right bank: fox, grain. Boat with man on right.",
"Fox and grain are safe together. Only chicken remains on left bank.",
NextAction.Continue,
0.95
));
Console.WriteLine(response8);

// Step 9: Think - Final Move
var response9 = await reasoningTool.ThinkAsync(new ThinkInput(
SessionId: sessionId,
Title: "Final Move",
Thought: "Go back empty, get chicken.",
Action: "Take chicken across",
Confidence: 1.0
sessionId,
"Final Move",
"Go back empty, get chicken.",
"Take chicken across",
1.0
));
Console.WriteLine(response9);

// Step 10: Analyze - Final State
var response10 = await reasoningTool.AnalyzeAsync(new AnalyzeInput(
SessionId: sessionId,
Title: "Final State",
Result: "Left bank: empty. Right bank: fox, chicken, grain, man.",
Analysis: "All items successfully transported. Puzzle solved!",
NextAction: NextAction.FinalAnswer,
Confidence: 1.0
sessionId,
"Final State",
"Left bank: empty. Right bank: fox, chicken, grain, man.",
"All items successfully transported. Puzzle solved!",
NextAction.FinalAnswer,
1.0
));
Console.WriteLine(response10);

Expand All @@ -131,7 +131,7 @@ public static async Task RunAsync()
{
var step = history[i];
Console.WriteLine($"Step {i + 1}: [{step.Type.ToUpper()}] {step.Title}");
Console.WriteLine($"Confidence: {step.Confidence:F2}");
Console.WriteLine($" {step.Confidence:F2}");
Console.WriteLine($"Timestamp: {step.Timestamp:yyyy-MM-dd HH:mm:ss}");
Console.WriteLine(step.Content);
Console.WriteLine();
Expand Down
1 change: 1 addition & 0 deletions src/AgenTerra.Core/AgenTerra.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.0" />
<PackageReference Include="PdfPig" Version="0.1.12" />
</ItemGroup>

Expand Down
11 changes: 9 additions & 2 deletions src/AgenTerra.Core/Reasoning/IReasoningTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,28 @@ public interface IReasoningTool
/// Records a thinking step with a thought and optional action.
/// </summary>
/// <param name="input">The thinking input containing the session ID, title, thought, and optional action.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>A formatted string response suitable for LLM consumption.</returns>
Task<string> ThinkAsync(ThinkInput input);
Task<string> ThinkAsync(ThinkInput input, CancellationToken cancellationToken = default);

/// <summary>
/// Records an analysis step with a result and analysis of the next action.
/// </summary>
/// <param name="input">The analysis input containing the session ID, title, result, analysis, and next action.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>A formatted string response suitable for LLM consumption.</returns>
Task<string> AnalyzeAsync(AnalyzeInput input);
Task<string> AnalyzeAsync(AnalyzeInput input, CancellationToken cancellationToken = default);

/// <summary>
/// Retrieves the complete reasoning history for a specific session.
/// </summary>
/// <param name="sessionId">The unique identifier of the session.</param>
/// <returns>An immutable list of reasoning steps for the session.</returns>
/// <remarks>
/// Warning: This method blocks synchronously to acquire a lock.
/// In ASP.NET or UI contexts with a synchronization context, this may cause deadlocks.
/// This method is synchronous to maintain backward compatibility.
/// </remarks>
IReadOnlyList<ReasoningStep> GetReasoningHistory(string sessionId);
}

Expand Down
62 changes: 47 additions & 15 deletions src/AgenTerra.Core/Reasoning/Models/AnalyzeInput.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,53 @@
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;

namespace AgenTerra.Core.Reasoning;

/// <summary>
/// Represents input for an analysis step in the reasoning process.
/// </summary>
/// <param name="SessionId">The unique identifier of the reasoning session.</param>
/// <param name="Title">A brief title describing this analysis step.</param>
/// <param name="Result">The result or observation being analyzed.</param>
/// <param name="Analysis">The analysis of the result.</param>
/// <param name="NextAction">The recommended next action in the reasoning process.</param>
/// <param name="Confidence">Confidence level in this analysis (0.0 to 1.0, default 0.8).</param>
public record AnalyzeInput(
[Required] string SessionId,
[Required] string Title,
[Required] string Result,
[Required] string Analysis,
NextAction NextAction = NextAction.Continue,
double Confidence = 0.8
);
public record AnalyzeInput
{
/// <summary>
/// Gets the unique identifier of the reasoning session.
/// </summary>
public required string SessionId { get; init; }

/// <summary>
/// Gets a brief title describing this analysis step.
/// </summary>
public required string Title { get; init; }

/// <summary>
/// Gets the result or observation being analyzed.
/// </summary>
public required string Result { get; init; }

/// <summary>
/// Gets the analysis of the result.
/// </summary>
public required string Analysis { get; init; }

/// <summary>
/// Gets the recommended next action in the reasoning process.
/// </summary>
public NextAction NextAction { get; init; } = NextAction.Continue;

/// <summary>
/// Gets the confidence level in this analysis (0.0 to 1.0).
/// </summary>
public double Confidence { get; init; } = 0.8;

/// <summary>
/// Initializes a new instance of the AnalyzeInput record with positional parameters (for backward compatibility).
/// </summary>
[SetsRequiredMembers]
public AnalyzeInput(string sessionId, string title, string result, string analysis, NextAction nextAction = NextAction.Continue, double confidence = 0.8)
{
SessionId = sessionId;
Title = title;
Result = result;
Analysis = analysis;
NextAction = nextAction;
Confidence = confidence;
}
}
21 changes: 21 additions & 0 deletions src/AgenTerra.Core/Reasoning/Models/ReasoningException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace AgenTerra.Core.Reasoning;

/// <summary>
/// Exception thrown when reasoning operations fail.
/// </summary>
public class ReasoningException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="ReasoningException"/> class with a specified error message.
/// </summary>
/// <param name="message">The message that describes the error.</param>
public ReasoningException(string message) : base(message) { }

/// <summary>
/// Initializes a new instance of the <see cref="ReasoningException"/> class with a specified error message and a reference to the inner exception.
/// </summary>
/// <param name="message">The message that describes the error.</param>
/// <param name="innerException">The exception that is the cause of the current exception.</param>
public ReasoningException(string message, Exception innerException)
: base(message, innerException) { }
}
39 changes: 27 additions & 12 deletions src/AgenTerra.Core/Reasoning/Models/ReasoningStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,30 @@ namespace AgenTerra.Core.Reasoning;
/// <summary>
/// Represents a single step in the reasoning process.
/// </summary>
/// <param name="Type">The type of step ("think" or "analyze").</param>
/// <param name="Title">A brief title describing this step.</param>
/// <param name="Content">The content of the reasoning step.</param>
/// <param name="Confidence">Confidence level in this step (0.0 to 1.0).</param>
/// <param name="Timestamp">When this step was recorded.</param>
public record ReasoningStep(
string Type,
string Title,
string Content,
double Confidence,
DateTime Timestamp
);
public record ReasoningStep
{
/// <summary>
/// Gets the type of step ("think" or "analyze").
/// </summary>
public required string Type { get; init; }

/// <summary>
/// Gets a brief title describing this step.
/// </summary>
public required string Title { get; init; }

/// <summary>
/// Gets the content of the reasoning step.
/// </summary>
public required string Content { get; init; }

/// <summary>
/// Gets the confidence level in this step (0.0 to 1.0).
/// </summary>
public required double Confidence { get; init; }

/// <summary>
/// Gets the timestamp when this step was recorded.
/// </summary>
public required DateTime Timestamp { get; init; }
}
Loading