mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Cleanup logging
This commit is contained in:
@@ -29,13 +29,10 @@ public partial class AgentStateBoundary<TState> : IComponent, IDisposable
|
||||
/// </summary>
|
||||
[Parameter] public EventCallback<IAgentBoundaryContext> OnContextCreated { get; set; }
|
||||
|
||||
[Inject] private ILogger<AgentStateBoundary<TState>> Logger { get; set; } = default!;
|
||||
|
||||
public void Attach(RenderHandle renderHandle)
|
||||
{
|
||||
this._renderHandle = renderHandle;
|
||||
this._renderWithState = this.RenderWithState;
|
||||
Log.AgentBoundaryAttached(this.Logger);
|
||||
}
|
||||
|
||||
// Agent boundary renders once when it receives the initial set of parameters
|
||||
@@ -62,17 +59,6 @@ public partial class AgentStateBoundary<TState> : IComponent, IDisposable
|
||||
|
||||
bool refresh = agentChanged || threadChanged || stateChanged;
|
||||
|
||||
Log.AgentBoundaryRefreshCheck(
|
||||
this.Logger,
|
||||
refresh,
|
||||
agentChanged,
|
||||
threadChanged,
|
||||
stateChanged,
|
||||
this.Agent?.GetHashCode() ?? 0,
|
||||
this._currentAgent?.GetHashCode() ?? 0,
|
||||
thread?.GetHashCode() ?? 0,
|
||||
this._currentThread?.GetHashCode() ?? 0);
|
||||
|
||||
if (refresh)
|
||||
{
|
||||
this._context?.Dispose();
|
||||
@@ -80,14 +66,12 @@ public partial class AgentStateBoundary<TState> : IComponent, IDisposable
|
||||
this._currentThread = null;
|
||||
}
|
||||
|
||||
Log.AgentBoundaryParametersSet(this.Logger, refresh);
|
||||
|
||||
this._currentAgent = this.Agent;
|
||||
this._currentThread = thread;
|
||||
|
||||
// Agent is validated non-null above, thread is either from Thread parameter or GetNewThread()
|
||||
bool isNewContext = this._context == null;
|
||||
this._context ??= new AgentBoundaryContext<TState>(this.Agent!, thread!, this.Logger);
|
||||
this._context ??= new AgentBoundaryContext<TState>(this.Agent!, thread!);
|
||||
this._context.CurrentState = this.State;
|
||||
|
||||
// Invoke the context created callback if we created a new context
|
||||
@@ -106,7 +90,6 @@ public partial class AgentStateBoundary<TState> : IComponent, IDisposable
|
||||
|
||||
private void Render()
|
||||
{
|
||||
Log.AgentBoundaryRendering(this.Logger);
|
||||
this._renderHandle.Render(builder =>
|
||||
{
|
||||
builder.OpenComponent<CascadingValue<AgentBoundaryContext<TState>>>(0);
|
||||
@@ -138,30 +121,11 @@ public partial class AgentStateBoundary<TState> : IComponent, IDisposable
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Log.AgentBoundaryDisposed(this.Logger);
|
||||
this._context?.Dispose();
|
||||
}
|
||||
this._disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static partial class Log
|
||||
{
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "AgentStateBoundary attached to render handle")]
|
||||
public static partial void AgentBoundaryAttached(ILogger logger);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "AgentStateBoundary refresh check: refresh={Refresh}, agentChanged={AgentChanged}, threadChanged={ThreadChanged}, stateChanged={StateChanged}, agentHash={AgentHash}, currentAgentHash={CurrentAgentHash}, threadHash={ThreadHash}, currentThreadHash={CurrentThreadHash}")]
|
||||
public static partial void AgentBoundaryRefreshCheck(ILogger logger, bool refresh, bool agentChanged, bool threadChanged, bool stateChanged, int agentHash, int currentAgentHash, int threadHash, int currentThreadHash);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "AgentStateBoundary parameters set, refresh required: {RefreshRequired}")]
|
||||
public static partial void AgentBoundaryParametersSet(ILogger logger, bool refreshRequired);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "AgentStateBoundary rendering")]
|
||||
public static partial void AgentBoundaryRendering(ILogger logger);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "AgentStateBoundary disposed")]
|
||||
public static partial void AgentBoundaryDisposed(ILogger logger);
|
||||
}
|
||||
}
|
||||
|
||||
public class AgentBoundary : AgentStateBoundary<object?>
|
||||
|
||||
@@ -10,7 +10,6 @@ public sealed partial class AgentBoundaryContext<TState> : IAgentBoundaryContext
|
||||
private readonly AIAgent _agent;
|
||||
private readonly AgentThread _thread;
|
||||
private readonly CancellationTokenSource _cancellationTokenSource;
|
||||
private readonly ILogger _logger;
|
||||
private readonly List<ChatMessage> _messages = [];
|
||||
private readonly List<ChatMessage> _pendingMessages = [];
|
||||
private readonly List<Action> _messageChangeSubscribers = [];
|
||||
@@ -30,15 +29,11 @@ public sealed partial class AgentBoundaryContext<TState> : IAgentBoundaryContext
|
||||
|
||||
public ChatResponseUpdate? CurrentUpdate { get; private set; }
|
||||
|
||||
ILogger IAgentBoundaryContext.Logger => this._logger;
|
||||
|
||||
public AgentBoundaryContext(AIAgent agent, AgentThread thread, ILogger logger)
|
||||
public AgentBoundaryContext(AIAgent agent, AgentThread thread)
|
||||
{
|
||||
this._agent = agent;
|
||||
this._thread = thread;
|
||||
this._cancellationTokenSource = new CancellationTokenSource();
|
||||
this._logger = logger;
|
||||
Log.AgentBoundaryContextCreated(this._logger);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -49,7 +44,6 @@ public sealed partial class AgentBoundaryContext<TState> : IAgentBoundaryContext
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(tool);
|
||||
this._tools.Add(tool);
|
||||
Log.ToolRegistered(this._logger, tool.Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -73,7 +67,6 @@ public sealed partial class AgentBoundaryContext<TState> : IAgentBoundaryContext
|
||||
{
|
||||
var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
this._pendingResponses[key] = tcs;
|
||||
Log.WaitForResponseStarted(this._logger, key);
|
||||
return tcs.Task;
|
||||
}
|
||||
|
||||
@@ -90,17 +83,14 @@ public sealed partial class AgentBoundaryContext<TState> : IAgentBoundaryContext
|
||||
{
|
||||
this._pendingResponses.Remove(key);
|
||||
tcs.TrySetResult(response);
|
||||
Log.ResponseProvided(this._logger, key);
|
||||
return true;
|
||||
}
|
||||
|
||||
Log.ResponseNotFound(this._logger, key);
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Log.AgentBoundaryContextDisposed(this._logger);
|
||||
this._cancellationTokenSource.Cancel();
|
||||
this._cancellationTokenSource.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
@@ -108,8 +98,6 @@ public sealed partial class AgentBoundaryContext<TState> : IAgentBoundaryContext
|
||||
|
||||
public async Task SendAsync(params ChatMessage[] userMessages)
|
||||
{
|
||||
Log.SendAsyncStarted(this._logger, userMessages.Length);
|
||||
|
||||
// This starts a new turn. Once completed, we will add the new messages to the conversation.
|
||||
this._pendingMessages.Clear();
|
||||
this._pendingMessages.AddRange(userMessages);
|
||||
@@ -125,7 +113,6 @@ public sealed partial class AgentBoundaryContext<TState> : IAgentBoundaryContext
|
||||
{
|
||||
Tools = [.. this._tools]
|
||||
});
|
||||
Log.RunningWithTools(this._logger, this._tools.Count);
|
||||
}
|
||||
|
||||
// Start a turn. Collect all updates as we stream them.
|
||||
@@ -138,16 +125,14 @@ public sealed partial class AgentBoundaryContext<TState> : IAgentBoundaryContext
|
||||
var chatUpdate = update.AsChatResponseUpdate();
|
||||
|
||||
this.CurrentUpdate = chatUpdate;
|
||||
Log.ChatResponseUpdateReceived(this._logger);
|
||||
|
||||
// Notify subscribers of the new update, this always happens before a new message is created/updated.
|
||||
this.TriggerChatResponseUpdate();
|
||||
|
||||
// This creates or adds a new message to the pending messages as needed.
|
||||
var isNewMessage = MessageHelpers.ProcessUpdate(chatUpdate, this._pendingMessages, this._logger);
|
||||
var isNewMessage = MessageHelpers.ProcessUpdate(chatUpdate, this._pendingMessages);
|
||||
if (isNewMessage)
|
||||
{
|
||||
Log.NewMessageCreated(this._logger, this._pendingMessages.Count);
|
||||
this.CurrentMessage = this._pendingMessages[this._pendingMessages.Count - 1];
|
||||
|
||||
// Finalize the previous message's content if we have 2 or more messages now.
|
||||
@@ -178,13 +163,10 @@ public sealed partial class AgentBoundaryContext<TState> : IAgentBoundaryContext
|
||||
// Notify subscribers
|
||||
this.TriggerChatResponseUpdate();
|
||||
this.TriggerMessageChanges();
|
||||
|
||||
Log.SendAsyncCompleted(this._logger, this._messages.Count);
|
||||
}
|
||||
|
||||
private void TriggerChatResponseUpdate()
|
||||
{
|
||||
Log.ResponseUpdateSubscribersNotified(this._logger, this._responseUpdateSubscribers.Count);
|
||||
// Iterate backwards to avoid issues if subscribers are removed during iteration
|
||||
for (var i = this._responseUpdateSubscribers.Count - 1; i >= 0; i--)
|
||||
{
|
||||
@@ -194,7 +176,6 @@ public sealed partial class AgentBoundaryContext<TState> : IAgentBoundaryContext
|
||||
|
||||
private void TriggerMessageChanges()
|
||||
{
|
||||
Log.MessageChangeSubscribersNotified(this._logger, this._messageChangeSubscribers.Count);
|
||||
// Iterate backwards to avoid issues if subscribers are removed during iteration
|
||||
for (var i = this._messageChangeSubscribers.Count - 1; i >= 0; i--)
|
||||
{
|
||||
@@ -211,48 +192,6 @@ public sealed partial class AgentBoundaryContext<TState> : IAgentBoundaryContext
|
||||
{
|
||||
return new ResponseUpdateSubscription(this._responseUpdateSubscribers, onChatResponse);
|
||||
}
|
||||
|
||||
private static partial class Log
|
||||
{
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "AgentBoundaryContext created for thread")]
|
||||
public static partial void AgentBoundaryContextCreated(ILogger logger);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "AgentBoundaryContext disposed")]
|
||||
public static partial void AgentBoundaryContextDisposed(ILogger logger);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "SendAsync started with {MessageCount} user message(s)")]
|
||||
public static partial void SendAsyncStarted(ILogger logger, int messageCount);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "SendAsync completed, total messages: {TotalMessages}")]
|
||||
public static partial void SendAsyncCompleted(ILogger logger, int totalMessages);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "New message created during streaming, pending count: {PendingCount}")]
|
||||
public static partial void NewMessageCreated(ILogger logger, int pendingCount);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "Chat response update received")]
|
||||
public static partial void ChatResponseUpdateReceived(ILogger logger);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "Message change subscribers notified, subscriber count: {SubscriberCount}")]
|
||||
public static partial void MessageChangeSubscribersNotified(ILogger logger, int subscriberCount);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "Response update subscribers notified, subscriber count: {SubscriberCount}")]
|
||||
public static partial void ResponseUpdateSubscribersNotified(ILogger logger, int subscriberCount);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "Tool registered: {ToolName}")]
|
||||
public static partial void ToolRegistered(ILogger logger, string toolName);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "Running with {ToolCount} registered tool(s)")]
|
||||
public static partial void RunningWithTools(ILogger logger, int toolCount);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "WaitForResponse started for key: {Key}")]
|
||||
public static partial void WaitForResponseStarted(ILogger logger, string key);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "Response provided for key: {Key}")]
|
||||
public static partial void ResponseProvided(ILogger logger, string key);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Warning, Message = "No pending response found for key: {Key}")]
|
||||
public static partial void ResponseNotFound(ILogger logger, string key);
|
||||
}
|
||||
}
|
||||
|
||||
public interface IAgentBoundaryContext
|
||||
@@ -271,8 +210,6 @@ public interface IAgentBoundaryContext
|
||||
|
||||
ChatResponseUpdate? CurrentUpdate { get; }
|
||||
|
||||
ILogger Logger { get; }
|
||||
|
||||
// Triggered any time there is a change on a message.
|
||||
MessageSubscription SubscribeToMessageChanges(Action onNewMessage);
|
||||
|
||||
|
||||
@@ -12,8 +12,6 @@ public partial class AgentInput : IComponent
|
||||
|
||||
[CascadingParameter] public AgentBoundaryContext<object?>? AgentContext { get; set; }
|
||||
|
||||
[Inject] private ILogger<AgentInput> Logger { get; set; } = default!;
|
||||
|
||||
[Parameter] public string Placeholder { get; set; } = "Type a message...";
|
||||
|
||||
public void Attach(RenderHandle renderHandle)
|
||||
@@ -25,14 +23,12 @@ public partial class AgentInput : IComponent
|
||||
{
|
||||
parameters.SetParameterProperties(this);
|
||||
this._context = this.AgentContext;
|
||||
Log.AgentInputAttached(this.Logger);
|
||||
this.Render();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void Render()
|
||||
{
|
||||
Log.AgentInputRendering(this.Logger);
|
||||
this._renderHandle.Render(builder =>
|
||||
{
|
||||
builder.OpenElement(0, "div");
|
||||
@@ -61,27 +57,10 @@ public partial class AgentInput : IComponent
|
||||
if (!string.IsNullOrWhiteSpace(this._inputText) && this._context != null)
|
||||
{
|
||||
var text = this._inputText;
|
||||
Log.AgentInputSendingMessage(this.Logger, text.Length);
|
||||
this._inputText = ""; // Clear input immediately
|
||||
this.Render(); // Re-render to clear input
|
||||
|
||||
await this._context.SendAsync(new ChatMessage(ChatRole.User, text));
|
||||
Log.AgentInputMessageSent(this.Logger);
|
||||
}
|
||||
}
|
||||
|
||||
private static partial class Log
|
||||
{
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "AgentInput attached to render handle")]
|
||||
public static partial void AgentInputAttached(ILogger logger);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "AgentInput rendering")]
|
||||
public static partial void AgentInputRendering(ILogger logger);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "AgentInput sending message: {MessageLength} characters")]
|
||||
public static partial void AgentInputSendingMessage(ILogger logger, int messageLength);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "AgentInput message sent successfully")]
|
||||
public static partial void AgentInputMessageSent(ILogger logger);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,7 +251,7 @@ internal static class MessageHelpers
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool ProcessUpdate(ChatResponseUpdate update, List<ChatMessage> messages, ILogger? logger = null)
|
||||
internal static bool ProcessUpdate(ChatResponseUpdate update, List<ChatMessage> messages)
|
||||
{
|
||||
// If there is no message created yet, or if the last update we saw had a different
|
||||
// identifying parts, create a new message.
|
||||
@@ -263,10 +263,6 @@ internal static class MessageHelpers
|
||||
NotEmptyOrEqual(update.AuthorName, lastMessage.AuthorName) ||
|
||||
NotEmptyOrEqual(update.MessageId, lastMessage.MessageId) ||
|
||||
NotNullOrEqual(update.Role, lastMessage.Role);
|
||||
|
||||
logger?.LogDebug(
|
||||
"ProcessUpdate checking: update.MessageId={UpdateMessageId}, lastMessage.MessageId={LastMessageId}, isNewMessage={IsNew}",
|
||||
update.MessageId, lastMessage.MessageId, isNewMessage);
|
||||
}
|
||||
|
||||
// Get the message to target, either a new one or the last ones.
|
||||
@@ -275,7 +271,6 @@ internal static class MessageHelpers
|
||||
{
|
||||
message = new(ChatRole.Assistant, []);
|
||||
messages.Add(message);
|
||||
logger?.LogDebug("ProcessUpdate: Created new message, total count={Count}", messages.Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -306,15 +301,12 @@ internal static class MessageHelpers
|
||||
{
|
||||
// Note that this must come after the message checks earlier, as they depend
|
||||
// on this value for change detection.
|
||||
var oldId = message.MessageId;
|
||||
message.MessageId = update.MessageId;
|
||||
logger?.LogDebug("ProcessUpdate: Set MessageId from {OldId} to {NewId}", oldId, update.MessageId);
|
||||
}
|
||||
|
||||
foreach (var content in update.Contents)
|
||||
{
|
||||
message.Contents.Add(content);
|
||||
logger?.LogDebug("ProcessUpdate: Added content type {ContentType}", content.GetType().Name);
|
||||
}
|
||||
|
||||
return isNewMessage;
|
||||
|
||||
@@ -34,8 +34,6 @@ internal sealed partial class MessageList : IComponent, IDisposable
|
||||
// Subscribe to message updates and response updates for streaming
|
||||
this._messageSubscription = this.MessageListContext.AgentBoundaryContext.SubscribeToMessageChanges(this.ProcessUpdate);
|
||||
this._responseSubscription = this.MessageListContext.AgentBoundaryContext.SubscribeToResponseUpdates(this.ProcessUpdate);
|
||||
Log.MessageListAttached(this.MessageListContext.AgentBoundaryContext.Logger);
|
||||
Log.MessageListSubscribed(this.MessageListContext.AgentBoundaryContext.Logger);
|
||||
|
||||
// Initial render. This component will only render once since the only parameter is a cascading parameter and it's fixed.
|
||||
this._renderHandle.Render(this.Render);
|
||||
@@ -77,11 +75,6 @@ internal sealed partial class MessageList : IComponent, IDisposable
|
||||
|
||||
public void Render(RenderTreeBuilder builder)
|
||||
{
|
||||
Log.MessageListRendering(
|
||||
this.MessageListContext.AgentBoundaryContext.Logger,
|
||||
this.MessageListContext.AgentBoundaryContext.CompletedMessages.Count,
|
||||
this.MessageListContext.AgentBoundaryContext.PendingMessages.Count);
|
||||
|
||||
// Track all render keys to detect duplicates
|
||||
var allRenderKeys = new HashSet<string?>();
|
||||
|
||||
@@ -89,21 +82,6 @@ internal sealed partial class MessageList : IComponent, IDisposable
|
||||
{
|
||||
var renderKey = GetUniqueRenderKey(message);
|
||||
|
||||
Log.RenderingCompletedMessage(
|
||||
this.MessageListContext.AgentBoundaryContext.Logger,
|
||||
message.MessageId,
|
||||
renderKey,
|
||||
message.Role.Value,
|
||||
message.Contents.Count);
|
||||
|
||||
if (renderKey != null && !allRenderKeys.Add(renderKey))
|
||||
{
|
||||
Log.DuplicateRenderKeyDetected(
|
||||
this.MessageListContext.AgentBoundaryContext.Logger,
|
||||
renderKey,
|
||||
"completed");
|
||||
}
|
||||
|
||||
// Calling GetTemplate will stop template collection on the first message if it
|
||||
// was still ongoing.
|
||||
builder.OpenComponent<ContentBlock>(0);
|
||||
@@ -116,21 +94,6 @@ internal sealed partial class MessageList : IComponent, IDisposable
|
||||
{
|
||||
var renderKey = GetUniqueRenderKey(message);
|
||||
|
||||
Log.RenderingPendingMessage(
|
||||
this.MessageListContext.AgentBoundaryContext.Logger,
|
||||
message.MessageId,
|
||||
renderKey,
|
||||
message.Role.Value,
|
||||
message.Contents.Count);
|
||||
|
||||
if (renderKey != null && !allRenderKeys.Add(renderKey))
|
||||
{
|
||||
Log.DuplicateRenderKeyDetected(
|
||||
this.MessageListContext.AgentBoundaryContext.Logger,
|
||||
renderKey,
|
||||
"pending");
|
||||
}
|
||||
|
||||
builder.OpenComponent<ContentBlock>(1);
|
||||
builder.SetKey(renderKey);
|
||||
builder.AddComponentParameter(1, "ChildContent", this.MessageListContext.GetTemplate(message));
|
||||
@@ -162,32 +125,7 @@ internal sealed partial class MessageList : IComponent, IDisposable
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Log.MessageListDisposed(this.MessageListContext.AgentBoundaryContext.Logger);
|
||||
((IDisposable)this._messageSubscription).Dispose();
|
||||
((IDisposable)this._responseSubscription).Dispose();
|
||||
}
|
||||
|
||||
private static partial class Log
|
||||
{
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "MessageList attached to render handle")]
|
||||
public static partial void MessageListAttached(ILogger logger);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "MessageList subscribed to message changes")]
|
||||
public static partial void MessageListSubscribed(ILogger logger);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "MessageList rendering, completed: {CompletedCount}, pending: {PendingCount}")]
|
||||
public static partial void MessageListRendering(ILogger logger, int completedCount, int pendingCount);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "Rendering completed message: MessageId={MessageId}, RenderKey={RenderKey}, Role={Role}, ContentCount={ContentCount}")]
|
||||
public static partial void RenderingCompletedMessage(ILogger logger, string? messageId, string? renderKey, string role, int contentCount);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "Rendering pending message: MessageId={MessageId}, RenderKey={RenderKey}, Role={Role}, ContentCount={ContentCount}")]
|
||||
public static partial void RenderingPendingMessage(ILogger logger, string? messageId, string? renderKey, string role, int contentCount);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Warning, Message = "DUPLICATE RenderKey detected: {RenderKey} in {Location} messages")]
|
||||
public static partial void DuplicateRenderKeyDetected(ILogger logger, string renderKey, string location);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "MessageList disposed")]
|
||||
public static partial void MessageListDisposed(ILogger logger);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ public sealed partial class MessageListContext
|
||||
public MessageListContext(IAgentBoundaryContext context)
|
||||
{
|
||||
this.AgentBoundaryContext = context;
|
||||
Log.MessageListContextCreated(this.AgentBoundaryContext.Logger);
|
||||
}
|
||||
|
||||
public IAgentBoundaryContext AgentBoundaryContext { get; }
|
||||
@@ -35,7 +34,6 @@ public sealed partial class MessageListContext
|
||||
this._templates.Clear();
|
||||
this._contentTemplates.Clear();
|
||||
this._templateCache.Clear();
|
||||
Log.BeganCollectingTemplates(this.AgentBoundaryContext.Logger);
|
||||
}
|
||||
|
||||
public void RegisterTemplate(MessageTemplateBase template)
|
||||
@@ -43,7 +41,6 @@ public sealed partial class MessageListContext
|
||||
if (this._collectingTemplates)
|
||||
{
|
||||
this._templates.Add(template);
|
||||
Log.MessageTemplateRegistered(this.AgentBoundaryContext.Logger, this._templates.Count);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +49,6 @@ public sealed partial class MessageListContext
|
||||
if (this._collectingTemplates)
|
||||
{
|
||||
this._contentTemplates.Add(template);
|
||||
Log.ContentTemplateRegistered(this.AgentBoundaryContext.Logger, this._contentTemplates.Count);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +63,6 @@ public sealed partial class MessageListContext
|
||||
{
|
||||
context = new InvocationContext(call);
|
||||
this._invocationMap[call.CallId] = context;
|
||||
Log.InvocationRegistered(this.AgentBoundaryContext.Logger, call.CallId, call.Name);
|
||||
}
|
||||
|
||||
return context;
|
||||
@@ -82,7 +77,6 @@ public sealed partial class MessageListContext
|
||||
if (this._invocationMap.TryGetValue(result.CallId, out var context))
|
||||
{
|
||||
context.SetResult(result);
|
||||
Log.ResultAssociated(this.AgentBoundaryContext.Logger, result.CallId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +114,6 @@ public sealed partial class MessageListContext
|
||||
// if it doesn't define the rendering for a content type.
|
||||
var renderer = chosen.ChildContent(messageContext);
|
||||
this._templateCache[message] = renderer;
|
||||
Log.TemplateResolved(this.AgentBoundaryContext.Logger, message.Role.Value);
|
||||
return renderer;
|
||||
}
|
||||
}
|
||||
@@ -141,28 +134,4 @@ public sealed partial class MessageListContext
|
||||
|
||||
throw new InvalidOperationException($"No content template found for content of type {content.GetType().Name}.");
|
||||
}
|
||||
|
||||
private static partial class Log
|
||||
{
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "MessageListContext created")]
|
||||
public static partial void MessageListContextCreated(ILogger logger);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "MessageListContext began collecting templates")]
|
||||
public static partial void BeganCollectingTemplates(ILogger logger);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "Message template registered, total: {TemplateCount}")]
|
||||
public static partial void MessageTemplateRegistered(ILogger logger, int templateCount);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "Content template registered, total: {TemplateCount}")]
|
||||
public static partial void ContentTemplateRegistered(ILogger logger, int templateCount);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "Template resolved for message with role: {Role}")]
|
||||
public static partial void TemplateResolved(ILogger logger, string role);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "Invocation registered for CallId: {CallId}, Function: {FunctionName}")]
|
||||
public static partial void InvocationRegistered(ILogger logger, string callId, string functionName);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "Result associated with CallId: {CallId}")]
|
||||
public static partial void ResultAssociated(ILogger logger, string callId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,9 +53,7 @@ public partial class Messages : IComponent
|
||||
|
||||
if (this._messageListContext == null)
|
||||
{
|
||||
Log.MessagesAttached(this._context.Logger);
|
||||
this._messageListContext = new MessageListContext(this.AgentContext);
|
||||
Log.MessagesInitialized(this._context.Logger);
|
||||
this.Render();
|
||||
}
|
||||
|
||||
@@ -64,7 +62,6 @@ public partial class Messages : IComponent
|
||||
|
||||
private void Render()
|
||||
{
|
||||
Log.MessagesRendering(this._context?.Logger!);
|
||||
this._renderHandle.Render(this.RenderCore);
|
||||
}
|
||||
|
||||
@@ -86,16 +83,4 @@ public partial class Messages : IComponent
|
||||
builder.OpenComponent<MessageList>(3);
|
||||
builder.CloseComponent();
|
||||
}
|
||||
|
||||
private static partial class Log
|
||||
{
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "Messages component attached to render handle")]
|
||||
public static partial void MessagesAttached(ILogger logger);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "Messages component initialized with MessageListContext")]
|
||||
public static partial void MessagesInitialized(ILogger logger);
|
||||
|
||||
[LoggerMessage(Level = LogLevel.Debug, Message = "Messages component rendering")]
|
||||
public static partial void MessagesRendering(ILogger logger);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
@* Copyright (c) Microsoft. All rights reserved. *@
|
||||
@using Microsoft.AspNetCore.Components.AI
|
||||
@using Microsoft.Extensions.AI
|
||||
@using Microsoft.Extensions.Logging
|
||||
@using System.Text.Json
|
||||
@implements IDisposable
|
||||
@inject ILogger<PlanCard> Logger
|
||||
|
||||
@if (IsWaitingForPlan)
|
||||
{
|
||||
@@ -139,21 +137,13 @@ else if (WasRejected)
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
Logger.LogInformation("PlanCard OnInitialized called");
|
||||
Logger.LogInformation("BoundaryContext is {Status}", BoundaryContext is null ? "NULL" : "present");
|
||||
Logger.LogInformation("Invocation is {Status}, HasResult: {HasResult}",
|
||||
Invocation is null ? "NULL" : "present",
|
||||
Invocation?.HasResult ?? false);
|
||||
|
||||
// The plan comes from the create_plan function result
|
||||
if (Invocation?.HasResult == true)
|
||||
{
|
||||
Logger.LogInformation("Invocation already has result, parsing plan");
|
||||
TryParsePlanFromResult();
|
||||
}
|
||||
else if (Invocation is not null)
|
||||
{
|
||||
Logger.LogInformation("Subscribing to Invocation.ResultArrived");
|
||||
// Subscribe to wait for the result
|
||||
Invocation.ResultArrived += OnCreatePlanResultArrived;
|
||||
}
|
||||
@@ -161,18 +151,12 @@ else if (WasRejected)
|
||||
// Subscribe to response updates to detect confirm_plan and update_plan_step calls
|
||||
if (BoundaryContext is not null)
|
||||
{
|
||||
Logger.LogInformation("Subscribing to response updates");
|
||||
_responseSubscription = BoundaryContext.SubscribeToResponseUpdates(OnResponseUpdate);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogWarning("BoundaryContext is null, cannot subscribe to response updates!");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCreatePlanResultArrived()
|
||||
{
|
||||
Logger.LogInformation("OnCreatePlanResultArrived called");
|
||||
TryParsePlanFromResult();
|
||||
InvokeAsync(StateHasChanged);
|
||||
}
|
||||
@@ -180,7 +164,6 @@ else if (WasRejected)
|
||||
private void TryParsePlanFromResult()
|
||||
{
|
||||
var plan = Invocation?.GetResult<Plan>();
|
||||
Logger.LogInformation("TryParsePlanFromResult: plan is {Status}", plan is null ? "NULL" : $"present with {plan.Steps.Count} steps");
|
||||
if (plan is not null)
|
||||
{
|
||||
CurrentPlan = plan;
|
||||
@@ -201,42 +184,30 @@ else if (WasRejected)
|
||||
selectedSteps.Add(i);
|
||||
}
|
||||
}
|
||||
Logger.LogInformation("InitializeSelectedSteps: selected {Count} steps", selectedSteps.Count);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnResponseUpdate()
|
||||
{
|
||||
Logger.LogInformation("OnResponseUpdate called");
|
||||
|
||||
// Check the current update for tool calls
|
||||
var update = BoundaryContext?.CurrentUpdate;
|
||||
if (update is null)
|
||||
{
|
||||
Logger.LogInformation("CurrentUpdate is null");
|
||||
return;
|
||||
}
|
||||
|
||||
Logger.LogInformation("CurrentUpdate has {Count} contents", update.Contents?.Count ?? 0);
|
||||
|
||||
if (update.Contents is not null)
|
||||
{
|
||||
foreach (var content in update.Contents)
|
||||
{
|
||||
Logger.LogInformation("Content type: {Type}", content.GetType().Name);
|
||||
|
||||
if (content is FunctionCallContent call)
|
||||
{
|
||||
Logger.LogInformation("Found FunctionCallContent: {Name}, CallId: {CallId}", call.Name, call.CallId);
|
||||
|
||||
if (string.Equals(call.Name, "confirm_plan", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.LogInformation("Detected confirm_plan call!");
|
||||
HandleConfirmPlanCall(call);
|
||||
}
|
||||
else if (string.Equals(call.Name, "update_plan_step", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.LogInformation("Detected update_plan_step call!");
|
||||
HandleUpdatePlanStepCall(call);
|
||||
}
|
||||
}
|
||||
@@ -248,15 +219,11 @@ else if (WasRejected)
|
||||
|
||||
private void HandleConfirmPlanCall(FunctionCallContent call)
|
||||
{
|
||||
Logger.LogInformation("HandleConfirmPlanCall: AwaitingConfirmation={Awaiting}, WasRejected={Rejected}, _confirmPlanCallId={CallId}",
|
||||
AwaitingConfirmation, WasRejected, _confirmPlanCallId);
|
||||
|
||||
// When confirm_plan is called, show the confirmation UI
|
||||
if (!AwaitingConfirmation && !WasRejected && _confirmPlanCallId is null)
|
||||
{
|
||||
_confirmPlanCallId = call.CallId;
|
||||
AwaitingConfirmation = true;
|
||||
Logger.LogInformation("Set AwaitingConfirmation to true, _confirmPlanCallId={CallId}", _confirmPlanCallId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,14 +231,12 @@ else if (WasRejected)
|
||||
{
|
||||
if (CurrentPlan is null)
|
||||
{
|
||||
Logger.LogWarning("HandleUpdatePlanStepCall: CurrentPlan is null");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the index and status from arguments
|
||||
if (call.Arguments is null)
|
||||
{
|
||||
Logger.LogWarning("HandleUpdatePlanStepCall: Arguments is null");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -298,9 +263,6 @@ else if (WasRejected)
|
||||
else if (descObj is JsonElement je && je.ValueKind == JsonValueKind.String) description = je.GetString();
|
||||
}
|
||||
|
||||
Logger.LogInformation("HandleUpdatePlanStepCall: index={Index}, status={Status}, description={Description}",
|
||||
index, status, description);
|
||||
|
||||
// Apply the update
|
||||
if (index.HasValue && index.Value >= 0 && index.Value < CurrentPlan.Steps.Count)
|
||||
{
|
||||
@@ -312,7 +274,6 @@ else if (WasRejected)
|
||||
{
|
||||
CurrentPlan.Steps[index.Value].Description = description;
|
||||
}
|
||||
Logger.LogInformation("Updated step {Index}", index.Value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,7 +292,6 @@ else if (WasRejected)
|
||||
|
||||
private void ConfirmPlan()
|
||||
{
|
||||
Logger.LogInformation("ConfirmPlan called with {Count} selected steps", selectedSteps.Count);
|
||||
AwaitingConfirmation = false;
|
||||
var result = new PlanConfirmationResult
|
||||
{
|
||||
@@ -343,7 +303,6 @@ else if (WasRejected)
|
||||
|
||||
private void RejectPlan()
|
||||
{
|
||||
Logger.LogInformation("RejectPlan called");
|
||||
WasRejected = true;
|
||||
AwaitingConfirmation = false;
|
||||
var result = new PlanConfirmationResult
|
||||
@@ -356,7 +315,6 @@ else if (WasRejected)
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Logger.LogInformation("PlanCard Dispose called");
|
||||
if (Invocation is not null)
|
||||
{
|
||||
Invocation.ResultArrived -= OnCreatePlanResultArrived;
|
||||
|
||||
-3
@@ -6,10 +6,8 @@
|
||||
@using AGUIDojoClient.Components.Shared
|
||||
@using System.Text.Json
|
||||
@using System.ComponentModel
|
||||
@using Microsoft.Extensions.Logging
|
||||
@implements IDisposable
|
||||
@inject IServiceProvider ServiceProvider
|
||||
@inject ILogger<PredictiveStateUpdatesDemo> Logger
|
||||
|
||||
<PageTitle>AI Document Editor</PageTitle>
|
||||
|
||||
@@ -148,7 +146,6 @@
|
||||
string.Equals(call.Name, "confirm_changes", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Show confirmation dialog when confirm_changes is called
|
||||
Logger.LogInformation("Detected confirm_changes call, showing confirmation dialog");
|
||||
awaitingConfirmation = true;
|
||||
isStreaming = false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user