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
11 changes: 11 additions & 0 deletions DurableMultiAgentTemplate.Client/Components/Pages/Home.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@

namespace DurableMultiAgentTemplate.Client.Components.Pages;

/// <summary>
/// Main home page component for the chat interface.
/// Handles user interactions and communication with agent services.
/// </summary>
public partial class Home(AgentChatService agentChatService, ILogger<Home> logger)
{
private const int _chatTimeoutMs = 60000;
Expand All @@ -17,6 +21,10 @@ public partial class Home(AgentChatService agentChatService, ILogger<Home> logge
private readonly List<ChatMessage> _messages = [];
private readonly List<IAdditionalInfo> _additionalInfo = [];

/// <summary>
/// Sends a message to the agent and processes the response.
/// Manages the UI state during the request/response cycle.
/// </summary>
private async Task SendMessageAsync()
{
void handleError(string originalInputMessage, string errorMessage)
Expand Down Expand Up @@ -105,6 +113,9 @@ static string createStatusMessage(AgentOrchestratorStatus status)
}
}

/// <summary>
/// Resets the chat interface by clearing all messages and additional information.
/// </summary>
private void Reset()
{
_messages.Clear();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
namespace DurableMultiAgentTemplate.Client.Components.Utilities;

/// <summary>
/// Context class for managing scroll-to-bottom operations in the UI.
/// Used to communicate scroll requests between components.
/// </summary>
public class ScrollToBottomContext
{
/// <summary>
/// Gets a value indicating whether a scroll to bottom operation has been requested.
/// </summary>
public bool IsRequestScrollToBottom { get; private set; }

/// <summary>
/// Requests a scroll to bottom operation.
/// Sets the IsRequestScrollToBottom flag to true.
/// </summary>
public void RequestScrollToBottom()
{
IsRequestScrollToBottom = true;
}

/// <summary>
/// Resets the scroll request.
/// Sets the IsRequestScrollToBottom flag to false.
/// </summary>
public void Reset()
{
IsRequestScrollToBottom = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,18 @@

namespace DurableMultiAgentTemplate.Client.Http;

/// <summary>
/// HTTP message handler that adds Azure Functions API key authentication to requests.
/// Implements the delegating handler pattern to inject authentication headers.
/// </summary>
public class AzureFunctionsApiKeyAuthenticationHttpMessageHandler(IOptions<BackendOptions> backendOptions) : DelegatingHandler
{
/// <summary>
/// Sends an HTTP request to the inner handler after adding the API key header if configured.
/// </summary>
/// <param name="request">The HTTP request message to send.</param>
/// <param name="cancellationToken">A cancellation token to cancel the operation.</param>
/// <returns>The HTTP response message.</returns>
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (!string.IsNullOrEmpty(backendOptions.Value.ApiKey))
Expand Down
11 changes: 11 additions & 0 deletions DurableMultiAgentTemplate.Client/Model/ChatInput.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
namespace DurableMultiAgentTemplate.Client.Model;

/// <summary>
/// Represents user chat input in the client application.
/// Contains the message text and a flag indicating whether additional information is required.
/// </summary>
public class ChatInput
{
/// <summary>
/// Gets or sets a value indicating whether the response should include additional information.
/// </summary>
public bool RequireAdditionalInfo { get; set; }

/// <summary>
/// Gets or sets the message content entered by the user.
/// </summary>
public string Message { get; set; } = "";
}
47 changes: 47 additions & 0 deletions DurableMultiAgentTemplate.Client/Model/ChatMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,67 @@

namespace DurableMultiAgentTemplate.Client.Model;

/// <summary>
/// Abstract record representing a chat message in the conversation.
/// Base class for different types of messages in the chat interface.
/// </summary>
/// <param name="Role">The role of the message sender.</param>
/// <param name="IsRequestTarget">Indicates whether the message is a target for a request.</param>
public abstract record ChatMessage(Role Role, bool IsRequestTarget);

/// <summary>
/// Record representing a message from the user.
/// </summary>
/// <param name="Message">The content of the user's message.</param>
public record UserChatMessage(string Message) : ChatMessage(Role.User, true);

/// <summary>
/// Record representing a message from the agent.
/// Contains the response data including any additional information.
/// </summary>
/// <param name="Message">The agent's response data.</param>
public record AgentChatMessage(AgentResponseWithAdditionalInfoDto Message) : ChatMessage(Role.Assistant, true);

/// <summary>
/// Record representing an informational message in the chat.
/// Used for system messages and status updates.
/// </summary>
/// <param name="Info">The informational text.</param>
/// <param name="IsShowProgress">Indicates whether to display progress information.</param>
public record InfoChatMessage(string Info, bool IsShowProgress) : ChatMessage(Role.Info, false);

/// <summary>
/// Enum defining the possible roles in a conversation.
/// </summary>
public enum Role
{
/// <summary>
/// Represents a human user.
/// </summary>
User,

/// <summary>
/// Represents an AI assistant.
/// </summary>
Assistant,

/// <summary>
/// Represents an informational system message.
/// </summary>
Info
}

/// <summary>
/// Extension methods for the Role enum.
/// </summary>
public static class RoleExtensions
{
/// <summary>
/// Converts a Role enum value to its string representation.
/// </summary>
/// <param name="role">The role to convert.</param>
/// <returns>String representation of the role.</returns>
/// <exception cref="InvalidOperationException">Thrown when an unsupported role is provided.</exception>
public static string ToRoleName(this Role role) => role switch
{
Role.User => "user",
Expand Down
20 changes: 20 additions & 0 deletions DurableMultiAgentTemplate.Client/Utilities/ExecutionTracker.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
namespace DurableMultiAgentTemplate.Client.Utilities;

/// <summary>
/// Tracks the execution state of operations.
/// Helps prevent concurrent operations by maintaining a flag for operations in progress.
/// </summary>
public class ExecutionTracker
{
/// <summary>
/// Gets a value indicating whether an operation is currently in progress.
/// </summary>
public bool IsInProgress { get; private set; }

/// <summary>
/// Starts tracking an execution and returns a disposable scope.
/// When the scope is disposed, the execution is marked as completed.
/// </summary>
/// <returns>A disposable scope that, when disposed, marks the execution as completed.</returns>
/// <exception cref="InvalidOperationException">Thrown if an execution is already in progress.</exception>
public Scope Start()
{
if (IsInProgress)
Expand All @@ -15,8 +28,15 @@ public Scope Start()
return new Scope(this);
}

/// <summary>
/// Represents a scope of execution.
/// When disposed, marks the associated execution tracker's operation as completed.
/// </summary>
public struct Scope(ExecutionTracker executionTracker) : IDisposable
{
/// <summary>
/// Marks the execution as completed.
/// </summary>
public void Dispose() => executionTracker.IsInProgress = false;
}
}
4 changes: 4 additions & 0 deletions DurableMultiAgentTemplate.Shared/Model/AgentResponseDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ public record AgentResponseDto(
string Content,
List<string> CalledAgentNames)
{
/// <summary>
/// Initializes a new instance of the AgentResponseDto class with empty called agent names.
/// </summary>
/// <param name="content">The content of the response.</param>
public AgentResponseDto(string content) : this(content, [])
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ public record AgentResponseWithAdditionalInfoDto(string Content,
List<string> CalledAgentNames,
List<IAdditionalInfo> AdditionalInfo) : AgentResponseDto(Content, CalledAgentNames)
{
/// <summary>
/// Initializes a new instance of the AgentResponseWithAdditionalInfoDto class with empty called agent names and additional info.
/// </summary>
/// <param name="content">The content of the response.</param>
public AgentResponseWithAdditionalInfoDto(string content) : this(content, [], [])
{
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,18 @@

namespace DurableMultiAgentTemplate.Agent.AgentDecider;

/// <summary>
/// Activity class responsible for determining which agent(s) should be called based on user request.
/// Analyzes user input and decides appropriate agent routing for the multi-agent system.
/// </summary>
public class AgentDeciderActivity(ChatClient chatClient, ILogger<AgentDeciderActivity> logger)
{
/// <summary>
/// Executes the agent decision logic to determine which agents should be called.
/// Analyzes user messages and uses OpenAI function calling to route to appropriate agents.
/// </summary>
/// <param name="reqData">Request data containing user messages and configuration</param>
/// <returns>Agent decision result indicating whether agent calls are needed and which agents to call</returns>
[Function(AgentActivityName.AgentDeciderActivity)]
public async Task<AgentDeciderResult> Run([ActivityTrigger] AgentRequestDto reqData)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
namespace DurableMultiAgentTemplate.Agent.AgentDecider;

/// <summary>
/// Static class containing prompt templates for the AgentDecider.
/// Provides the system prompt used to guide the agent's decision-making process.
/// </summary>
internal static class AgentDeciderPrompt
{
// Orchestrator Agent functions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,19 @@

namespace DurableMultiAgentTemplate.Agent.GetClimateAgent;

/// <summary>
/// Activity class responsible for retrieving climate information for a specified location.
/// Part of the multi-agent travel concierge system.
/// </summary>
public class GetClimateActivity(ChatClient chatClient,

Check warning on line 11 in DurableMultiAgentTemplate/Agent/GetClimateAgent/GetClimateActivity.cs

View workflow job for this annotation

GitHub Actions / build-and-test-ubuntu-latest

Parameter 'chatClient' is unread.

Check warning on line 11 in DurableMultiAgentTemplate/Agent/GetClimateAgent/GetClimateActivity.cs

View workflow job for this annotation

GitHub Actions / build-and-test-ubuntu-latest

Parameter 'chatClient' is unread.
ILogger<GetClimateActivity> logger)
{
/// <summary>
/// Retrieves climate information for the specified location.
/// Simulates a network call with potential failures and returns detailed climate data.
/// </summary>
/// <param name="req">Request containing the location for which to retrieve climate information</param>
/// <returns>Detailed climate information for the specified location in Japanese</returns>
[Function(AgentActivityName.GetClimateAgent)]
public async Task<string> RunAsync([ActivityTrigger] GetClimateRequest req)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

namespace DurableMultiAgentTemplate.Agent.GetClimateAgent;

/// <summary>
/// Record representing a request to retrieve climate information.
/// Used as input for the GetClimateActivity.
/// </summary>
public record GetClimateRequest(
[property: Description("場所の名前。例: ボストン, 東京、フランス")]
string Location);
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,19 @@

namespace DurableMultiAgentTemplate.Agent.GetDestinationSuggestAgent;

/// <summary>
/// Activity class responsible for suggesting travel destinations based on user preferences.
/// Provides recommendations for both domestic and international locations.
/// </summary>
public class GetDestinationSuggestActivity(ChatClient chatClient,

Check warning on line 11 in DurableMultiAgentTemplate/Agent/GetDestinationSuggestAgent/GetDestinationSuggestActivity.cs

View workflow job for this annotation

GitHub Actions / build-and-test-ubuntu-latest

Parameter 'chatClient' is unread.

Check warning on line 11 in DurableMultiAgentTemplate/Agent/GetDestinationSuggestAgent/GetDestinationSuggestActivity.cs

View workflow job for this annotation

GitHub Actions / build-and-test-ubuntu-latest

Parameter 'chatClient' is unread.
ILogger<GetDestinationSuggestActivity> logger)
{
/// <summary>
/// Generates travel destination suggestions based on the provided search criteria.
/// Simulates a network call with potential failures and returns categorized destination recommendations.
/// </summary>
/// <param name="req">Request containing search terms and criteria for destination suggestions</param>
/// <returns>Categorized destination suggestions (domestic and international) in Japanese</returns>
[Function(AgentActivityName.GetDestinationSuggestAgent)]
public async Task<string> RunAsync([ActivityTrigger] GetDestinationSuggestRequest req)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

namespace DurableMultiAgentTemplate.Agent.GetDestinationSuggestAgent;

/// <summary>
/// Record representing a request to suggest travel destinations.
/// Used as input for the GetDestinationSuggestActivity.
/// </summary>
public record GetDestinationSuggestRequest(
[property: Description("行き先に求める希望の条件")]
string SearchTerm);
10 changes: 10 additions & 0 deletions DurableMultiAgentTemplate/Agent/GetHotelAgent/GetHotelActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,19 @@

namespace DurableMultiAgentTemplate.Agent.GetHotelAgent;

/// <summary>
/// Activity class responsible for retrieving hotel information for a specified location.
/// Part of the multi-agent travel concierge system.
/// </summary>
public class GetHotelActivity(ChatClient chatClient,

Check warning on line 11 in DurableMultiAgentTemplate/Agent/GetHotelAgent/GetHotelActivity.cs

View workflow job for this annotation

GitHub Actions / build-and-test-ubuntu-latest

Parameter 'chatClient' is unread.

Check warning on line 11 in DurableMultiAgentTemplate/Agent/GetHotelAgent/GetHotelActivity.cs

View workflow job for this annotation

GitHub Actions / build-and-test-ubuntu-latest

Parameter 'chatClient' is unread.
ILogger<GetHotelActivity> logger)
{
/// <summary>
/// Retrieves hotel information for the specified location.
/// Simulates a network call with potential failures and returns hotel recommendations.
/// </summary>
/// <param name="req">Request containing the location for which to retrieve hotel information</param>
/// <returns>Detailed hotel recommendations for the specified location in Japanese</returns>
[Function(AgentActivityName.GetHotelAgent)]
public async Task<string> Run([ActivityTrigger] GetHotelRequest req)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

namespace DurableMultiAgentTemplate.Agent.GetHotelAgent;

/// <summary>
/// Record representing a request to retrieve hotel information.
/// Used as input for the GetHotelActivity.
/// </summary>
public record GetHotelRequest(
[property: Description("場所の名前。例: ボストン, 東京、フランス")]
string Location);
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,19 @@

namespace DurableMultiAgentTemplate.Agent.GetSightseeingSpotAgent;

/// <summary>
/// Activity class responsible for providing information about sightseeing spots at a specified location.
/// Delivers details about temples, natural attractions, beaches, cultural experiences, and activities.
/// </summary>
public class GetSightseeingSpotActivity(ChatClient chatClient,

Check warning on line 11 in DurableMultiAgentTemplate/Agent/GetSightseeingSpotAgent/GetSightseeingSpotActivity.cs

View workflow job for this annotation

GitHub Actions / build-and-test-ubuntu-latest

Parameter 'chatClient' is unread.

Check warning on line 11 in DurableMultiAgentTemplate/Agent/GetSightseeingSpotAgent/GetSightseeingSpotActivity.cs

View workflow job for this annotation

GitHub Actions / build-and-test-ubuntu-latest

Parameter 'chatClient' is unread.
ILogger<GetSightseeingSpotActivity> logger)
{
/// <summary>
/// Retrieves detailed information about sightseeing spots at the specified location.
/// Simulates a network call with potential failures and returns comprehensive attraction recommendations.
/// </summary>
/// <param name="req">Request containing the location for which to retrieve sightseeing information</param>
/// <returns>Detailed information about temples, nature spots, beaches, cultural experiences, and activities in Japanese</returns>
[Function(AgentActivityName.GetSightseeingSpotAgent)]
public async Task<string> RunAsync([ActivityTrigger] GetSightseeingSpotRequest req)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

namespace DurableMultiAgentTemplate.Agent.GetSightseeingSpotAgent;

/// <summary>
/// Record representing a request to retrieve sightseeing spot information.
/// Used as input for the GetSightseeingSpotActivity.
/// </summary>
public record GetSightseeingSpotRequest(
[property: Description("場所の名前。例: ボストン, 東京、フランス")]
string Location);
Loading