diff --git a/dotnet/samples/03-workflows/Agents/CustomAgentExecutors/Program.cs b/dotnet/samples/03-workflows/Agents/CustomAgentExecutors/Program.cs index e2dec8505b..41b622fdad 100644 --- a/dotnet/samples/03-workflows/Agents/CustomAgentExecutors/Program.cs +++ b/dotnet/samples/03-workflows/Agents/CustomAgentExecutors/Program.cs @@ -61,6 +61,12 @@ public static class Program { Console.WriteLine($"{outputEvent}"); } + + if (evt is WorkflowErrorEvent errorEvent) + { + Console.WriteLine($"Workflow error: {errorEvent.Exception?.Message}"); + Console.WriteLine($"Details: {errorEvent.Exception}"); + } } } } @@ -175,7 +181,9 @@ internal sealed class FeedbackEvent(FeedbackResult feedbackResult) : WorkflowEve /// /// A custom executor that uses an AI agent to provide feedback on a slogan. /// -internal sealed class FeedbackExecutor : Executor +[SendsMessage(typeof(FeedbackResult))] +[YieldsOutput(typeof(string))] +internal sealed partial class FeedbackExecutor : Executor { private readonly AIAgent _agent; private AgentSession? _session; diff --git a/dotnet/src/Microsoft.Agents.AI.Workflows.Generators/Analysis/SemanticAnalyzer.cs b/dotnet/src/Microsoft.Agents.AI.Workflows.Generators/Analysis/SemanticAnalyzer.cs index b62377a971..c116587507 100644 --- a/dotnet/src/Microsoft.Agents.AI.Workflows.Generators/Analysis/SemanticAnalyzer.cs +++ b/dotnet/src/Microsoft.Agents.AI.Workflows.Generators/Analysis/SemanticAnalyzer.cs @@ -212,6 +212,7 @@ internal static class SemanticAnalyzer bool isPartialClass = IsPartialClass(classSymbol, cancellationToken); bool derivesFromExecutor = DerivesFromExecutor(classSymbol); bool hasManualConfigureProtocol = HasConfigureProtocolDefined(classSymbol); + bool baseHasConfigureProtocol = BaseHasConfigureProtocol(classSymbol); string? @namespace = classSymbol.ContainingNamespace?.IsGlobalNamespace == true ? null @@ -241,6 +242,7 @@ internal static class SemanticAnalyzer isPartialClass, derivesFromExecutor, hasManualConfigureProtocol, + baseHasConfigureProtocol, classLocation, typeName, attributeKind)); @@ -321,7 +323,7 @@ internal static class SemanticAnalyzer first.GenericParameters, first.IsNested, first.ContainingTypeChain, - BaseHasConfigureProtocol: false, // Not relevant for protocol-only + first.BaseHasConfigureProtocol, Handlers: ImmutableEquatableArray.Empty, ClassSendTypes: new ImmutableEquatableArray(sendTypes.ToImmutable()), ClassYieldTypes: new ImmutableEquatableArray(yieldTypes.ToImmutable())); diff --git a/dotnet/src/Microsoft.Agents.AI.Workflows.Generators/Models/ClassProtocolInfo.cs b/dotnet/src/Microsoft.Agents.AI.Workflows.Generators/Models/ClassProtocolInfo.cs index df9205cc5f..90e5762890 100644 --- a/dotnet/src/Microsoft.Agents.AI.Workflows.Generators/Models/ClassProtocolInfo.cs +++ b/dotnet/src/Microsoft.Agents.AI.Workflows.Generators/Models/ClassProtocolInfo.cs @@ -16,6 +16,7 @@ namespace Microsoft.Agents.AI.Workflows.Generators.Models; /// Whether the class is declared as partial. /// Whether the class derives from Executor. /// Whether the class has a manually defined ConfigureRoutes method. +/// Whether a base class already overrides ConfigureProtocol. /// Location info for diagnostics. /// The fully qualified type name from the attribute. /// Whether this is from a SendsMessage or YieldsOutput attribute. @@ -29,6 +30,7 @@ internal sealed record ClassProtocolInfo( bool IsPartialClass, bool DerivesFromExecutor, bool HasManualConfigureRoutes, + bool BaseHasConfigureProtocol, DiagnosticLocationInfo? ClassLocation, string TypeName, ProtocolAttributeKind AttributeKind) @@ -38,5 +40,5 @@ internal sealed record ClassProtocolInfo( /// public static ClassProtocolInfo Empty { get; } = new( string.Empty, null, string.Empty, null, false, string.Empty, - false, false, false, null, string.Empty, ProtocolAttributeKind.Send); + false, false, false, false, null, string.Empty, ProtocolAttributeKind.Send); }