You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
.NET: Latest release changes WorkflowBuilder API #1305
There should not be any changes here. Do you have a code sample that used to work and doesn't now? - and were there other changes you made?
ExecutorIsh was the top-level input since the very beginning, and this has not changed, so I am unsure what is causing you to need to explicitly cast to it now?
With that said: ExecutorIsh is likely to undergo further changes, but in principle, being able to pass in Executors, Agents, etc. directly to the builder APIs should remain.
I pasted a sample in the original issue, I don't know what more to say? I could pass agents in, then I pulled a nuget update after which I had to wrap them in Executorish.
From Stephen's linked issue, it seems there was some implicit casting going on under the surface which F# doesn't tend to play along with, so perhaps it doesn't show up in C#? It was working before I pulled the update anyway so something must have changed in the implementation.
I pasted a sample in the original issue, I don't know what more to say
I was just trying to warp my head around what could have changed, since the only input type that the WorkflowBuilder APIs ever took was ExecutorIsh - there was never a point at which it took Agent directly. It is odd that it used to work with the implicit cast and now fails.
Still, will need to think about how to make this work nicely from F#. You may never have as "nice" as interface as C# unless I add some special-casing.
Do you know if there is a way for me to add special overloads that are F# specific that present the API as a type union?
I suggest the WorkflowBuilder APIs should just be in terms of Executor, and anything else (AIAgent, etc.) should be explicitly converted to an Executor, either via a ToXx extension method, or overloads of an Executor.Create method with an overload for each type, or some such thing. I don't think cuteness with implicit operators is a good way to go, even if it makes the code a little more terse.
Perhaps rather than have an option (implicit casting) that only works in C# and another (unions) that only works in F#, a simple solution that works for both would be constructor overloads for either Executor or Agent, then the framework sorts it out internally?
The issue with that is that we need to be able to have collections of any of the following (somewhat) unrelated types and would prefer not to force everyone to wrap it in a wrapper (kind of like you had to wrap in "ExecutorIsh"). That's what I am trying to do: Get back to being able to pass both AIAgent, and Executor instances, as well as configured factories and things like RequestPort and Workflow directly.
My goal is to make the simple case simple. I will add as many special-casings, even up to language-specific ones, to make that work.
My question is: What will be necessary to make it work nicely in F#. I know how to make it nice in C#.
Beyond making the consumption of the APIs nice in the simple case for developers, I genuinely do not have a strong opinion as to how it should be done: Happy to include all of the above.
Given you want to mix them in a list, then overloads aren't a way forward.
I'd really recommend against trying to make F# and C# specific APIs.
I agree with Stephen Toub (@stephentoub) - just add AsExecutor() methods to any classes you want to be able to use in an Executor context?
There is already a precedent for this in the functional API that I only discovered through this issue (which I much prefer and think should be promoted over the verbose classes, but I am an F# guy haha) : #1505
Another option would be to make them all implement an IExecutor interface?
just add AsExecutor() methods to any classes you want to be able to use in an Executor context?
That would add to the boilerplate / wordiness that is already raised as an isue in #1505. I genuinely would prefer to special-case it per language to avoid having 30% of the workflow construction just be ToExecutor() calls
AIAgent is in an assembly that Workflows depends on, so we would need to upstream ICanBeExecutor... and it would just be a "tag" interface, which is not ideal, or the abstractions library will need to pick up Workflow concepts which has its own drawbacks.
Going to experiment with this a little - see if I can merge the concepts of ExecutorRegistration and ExecutorIsh and at least implement the following:
A ToExecutor() (or RegisterExecutor()) extension method on all of the relevant types to create the appropriate ExecutorRegistration
The implicit casts for C#
After we can see if there is syntactic sugar we can add to the F# side to get back to "no cast, no ToExecutor" like it was before. I am confused how it ever worked, honestly.
(FWIW, I'm still not a fan of the implicit casts. I get that it removes a small amount of ceremony from the code, but that's a double-edged sword. It makes the code harder to understand because of these magic conversions happening between unrelated types, there are hidden performance implications, reference equality goes out the window which is very unexpected when it just looks like an assignment, etc.)
Ryan Palmer (@Ryan-Palmer), friendly reminder — this issue is waiting on your response. Please share any updates when you get a chance. (This is an automated message.)
Activity
stephentoub commentedon Oct 8, 2025
100%
#758
[-]Latest release changes WorkflowBuilder API[/-][+].NET: Latest release changes WorkflowBuilder API[/+]Ryan-Palmer commentedon Oct 8, 2025
Ah I guess the implicit casting you mentioned has been removed (yay!) but the ExecutorIsh remains (boo!)
lokitoth commentedon Oct 13, 2025
There should not be any changes here. Do you have a code sample that used to work and doesn't now? - and were there other changes you made?
ExecutorIsh was the top-level input since the very beginning, and this has not changed, so I am unsure what is causing you to need to explicitly cast to it now?
With that said: ExecutorIsh is likely to undergo further changes, but in principle, being able to pass in Executors, Agents, etc. directly to the builder APIs should remain.
Ryan-Palmer commentedon Oct 14, 2025
teknikal-wizard commentedon Oct 14, 2025
(Ryan from another account)
Looks like F# won't play with implicit operators as I suspected:
https://stackoverflow.com/questions/10719770/is-there-anyway-to-use-c-sharp-implicit-operators-from-f
agent-framework/dotnet/src/Microsoft.Agents.AI.Workflows/ExecutorIsh.cs
Line 287 in 9148392
Given that this is a .NET library rather than a C# app, I would suggest not leaning on C# only features if at all possible.
I don't know how it worked before, perhaps there were overloaded methods?
lokitoth commentedon Oct 20, 2025
I was just trying to warp my head around what could have changed, since the only input type that the
WorkflowBuilderAPIs ever took wasExecutorIsh- there was never a point at which it tookAgentdirectly. It is odd that it used to work with the implicit cast and now fails.Still, will need to think about how to make this work nicely from F#. You may never have as "nice" as interface as C# unless I add some special-casing.
Do you know if there is a way for me to add special overloads that are F# specific that present the API as a type union?
stephentoub commentedon Oct 20, 2025
I suggest the WorkflowBuilder APIs should just be in terms of Executor, and anything else (AIAgent, etc.) should be explicitly converted to an Executor, either via a ToXx extension method, or overloads of an Executor.Create method with an overload for each type, or some such thing. I don't think cuteness with implicit operators is a good way to go, even if it makes the code a little more terse.
Ryan-Palmer commentedon Oct 20, 2025
Perhaps rather than have an option (implicit casting) that only works in C# and another (unions) that only works in F#, a simple solution that works for both would be constructor overloads for either Executor or Agent, then the framework sorts it out internally?
lokitoth commentedon Oct 21, 2025
The issue with that is that we need to be able to have collections of any of the following (somewhat) unrelated types and would prefer not to force everyone to wrap it in a wrapper (kind of like you had to wrap in "
ExecutorIsh"). That's what I am trying to do: Get back to being able to pass bothAIAgent, andExecutorinstances, as well as configured factories and things likeRequestPortandWorkflowdirectly.E.g., the following should still work:
My goal is to make the simple case simple. I will add as many special-casings, even up to language-specific ones, to make that work.
My question is: What will be necessary to make it work nicely in F#. I know how to make it nice in C#.
Beyond making the consumption of the APIs nice in the simple case for developers, I genuinely do not have a strong opinion as to how it should be done: Happy to include all of the above.
Ryan-Palmer commentedon Oct 21, 2025
Given you want to mix them in a list, then overloads aren't a way forward.
I'd really recommend against trying to make F# and C# specific APIs.
I agree with Stephen Toub (@stephentoub) - just add
AsExecutor()methods to any classes you want to be able to use in an Executor context?There is already a precedent for this in the functional API that I only discovered through this issue (which I much prefer and think should be promoted over the verbose classes, but I am an F# guy haha) : #1505
Another option would be to make them all implement an
IExecutorinterface?lokitoth commentedon Oct 21, 2025
That would add to the boilerplate / wordiness that is already raised as an isue in #1505. I genuinely would prefer to special-case it per language to avoid having 30% of the workflow construction just be
ToExecutor()callsRyan-Palmer commentedon Oct 21, 2025
That's fair, but a language specific API would be confusing and I think is generally frowned upon for a general .NET library.
Don Syme (@dsyme) Isaac Abraham (@isaacabraham) perhaps you have an opinion here?
How about an
IExecutorinterface? That would have been my first thought if I needed to mix them in a collection.lokitoth commentedon Oct 21, 2025
AIAgentis in an assembly that Workflows depends on, so we would need to upstreamICanBeExecutor... and it would just be a "tag" interface, which is not ideal, or the abstractions library will need to pick up Workflow concepts which has its own drawbacks.Going to experiment with this a little - see if I can merge the concepts of
ExecutorRegistrationandExecutorIshand at least implement the following:ToExecutor()(orRegisterExecutor()) extension method on all of the relevant types to create the appropriateExecutorRegistrationAfter we can see if there is syntactic sugar we can add to the F# side to get back to "no cast, no
ToExecutor" like it was before. I am confused how it ever worked, honestly.stephentoub commentedon Oct 21, 2025
(FWIW, I'm still not a fan of the implicit casts. I get that it removes a small amount of ceremony from the code, but that's a double-edged sword. It makes the code harder to understand because of these magic conversions happening between unrelated types, there are hidden performance implications, reference equality goes out the window which is very unexpected when it just looks like an assignment, etc.)
markwallace-microsoft commentedon Mar 20, 2026
Ryan Palmer (@Ryan-Palmer), friendly reminder — this issue is waiting on your response. Please share any updates when you get a chance. (This is an automated message.)
alliscode commentedon Jun 2, 2026
Resolved by #1637