diff --git a/dotnet/src/Microsoft.Agents.Workflows.Declarative/AzureAgentProvider.cs b/dotnet/src/Microsoft.Agents.Workflows.Declarative/AzureAgentProvider.cs
index b3a0d044db..09a9db35a8 100644
--- a/dotnet/src/Microsoft.Agents.Workflows.Declarative/AzureAgentProvider.cs
+++ b/dotnet/src/Microsoft.Agents.Workflows.Declarative/AzureAgentProvider.cs
@@ -1,5 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
-
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
@@ -43,15 +42,20 @@ public sealed class AzureAgentProvider(string projectEndpoint, TokenCredential p
}
///
- public override async Task CreateMessageAsync(string conversationId, ChatMessage conversationMessage, CancellationToken cancellationToken = default)
+ public override Task CreateMessageAsync(string conversationId, ChatMessage conversationMessage, CancellationToken cancellationToken = default)
{
- await this.GetAgentsClient().Messages.CreateMessageAsync(
+ // TODO: Switch to asynchronous "CreateMessageAsync", when fix properly applied:
+ // BUG: https://github.com/Azure/azure-sdk-for-net/issues/52571
+ // PR: https://github.com/Azure/azure-sdk-for-net/pull/52653
+ this.GetAgentsClient().Messages.CreateMessage(
conversationId,
role: s_roleMap[conversationMessage.Role.Value.ToUpperInvariant()],
contentBlocks: GetContent(),
attachments: null,
metadata: GetMetadata(),
- cancellationToken).ConfigureAwait(false);
+ cancellationToken);
+
+ return Task.CompletedTask;
Dictionary? GetMetadata()
{
diff --git a/dotnet/src/Microsoft.Agents.Workflows.Declarative/Extensions/IWorkflowContextExtensions.cs b/dotnet/src/Microsoft.Agents.Workflows.Declarative/Extensions/IWorkflowContextExtensions.cs
index b370d6bae0..1ea2f6c8df 100644
--- a/dotnet/src/Microsoft.Agents.Workflows.Declarative/Extensions/IWorkflowContextExtensions.cs
+++ b/dotnet/src/Microsoft.Agents.Workflows.Declarative/Extensions/IWorkflowContextExtensions.cs
@@ -1,5 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.
+using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Agents.Workflows.Declarative.Interpreter;
@@ -36,6 +37,35 @@ internal static class IWorkflowContextExtensions
public static FormulaValue ReadState(this IWorkflowContext context, string key, string? scopeName = null) =>
DeclarativeContext(context).State.Get(key, scopeName);
+ public static async ValueTask QueueConversationUpdateAsync(this IWorkflowContext context, string conversationId)
+ {
+ RecordValue conversation = (RecordValue)context.ReadState(SystemScope.Names.Conversation, VariableScopeNames.System);
+ conversation.UpdateField("Id", FormulaValue.New(conversationId));
+ await context.QueueSystemUpdateAsync(SystemScope.Names.Conversation, conversation).ConfigureAwait(false);
+ await context.QueueSystemUpdateAsync(SystemScope.Names.ConversationId, FormulaValue.New(conversationId)).ConfigureAwait(false);
+
+ await context.AddEventAsync(new ConversationUpdateEvent(conversationId)).ConfigureAwait(false);
+ }
+
+ // Ensure "System.Conversation.Id" and "System.ConversationId" are properly initialized when referenced.
+ public static async ValueTask EnsureWorkflowConversationAsync(this IWorkflowContext context, WorkflowAgentProvider agentProvider, StringExpression expression, CancellationToken cancellationToken)
+ {
+ if (expression.IsVariableReference &&
+ expression.VariableReference.IsVariableReferenceWithScope(VariableScopeNames.System, out string? variableName))
+ {
+ if (string.Equals(variableName, SystemScope.Names.Conversation, StringComparison.Ordinal) ||
+ string.Equals(variableName, SystemScope.Names.ConversationId, StringComparison.Ordinal))
+ {
+ FormulaValue variableValue = context.ReadState(SystemScope.Names.ConversationId, VariableScopeNames.System);
+ if (variableValue is BlankValue)
+ {
+ string conversationId = await agentProvider.CreateConversationAsync(cancellationToken).ConfigureAwait(false);
+ await context.QueueConversationUpdateAsync(conversationId).ConfigureAwait(false);
+ }
+ }
+ }
+ }
+
private static DeclarativeWorkflowContext DeclarativeContext(IWorkflowContext context)
{
if (context is not DeclarativeWorkflowContext declarativeContext)
diff --git a/dotnet/src/Microsoft.Agents.Workflows.Declarative/ObjectModel/AddConversationMessageExecutor.cs b/dotnet/src/Microsoft.Agents.Workflows.Declarative/ObjectModel/AddConversationMessageExecutor.cs
index 2cf6ffd6ac..4944d15552 100644
--- a/dotnet/src/Microsoft.Agents.Workflows.Declarative/ObjectModel/AddConversationMessageExecutor.cs
+++ b/dotnet/src/Microsoft.Agents.Workflows.Declarative/ObjectModel/AddConversationMessageExecutor.cs
@@ -17,8 +17,10 @@ internal sealed class AddConversationMessageExecutor(AddConversationMessage mode
{
protected override async ValueTask