Commit Graph
34 Commits
Author SHA1 Message Date
Jacob AlberandGitHub a39e6561fd .NET: fix: WorkflowAsAgent Sample (#1787)
* fix: WorkflowAsAgent Sample

* Also makes ChatForwardingExecutor public

* feat: Expand ChatForwardingExecutor handled types

Make ChatForwardingExecutor match the input types of ChatProtocolExecutor.

* fix: Update for the new AgentRunResponseUpdate merge logic

AIAgent always sends out List<ChatMessage> now.
2025-11-11 16:35:22 +00:00
Jacob AlberandGitHub 0bf6d437d8 .NET: [BREAKING] .NET: Add Workflow on-Build() Orphan Validation (#1943)
* fix: Workflow Validation

* adds orphan validation to workflow builder
* adds tests for workflow validation
* expands on the underlying reasoning why type validation is not supported

* fixup: CodeGen template
2025-11-05 22:12:27 +00:00
Jacob AlberandGitHub 94a5ba3448 .NET: [BREAKING] refactor: Normalize WorkflowBuilder APIs (#1935)
* [BREAKING] refactor: Normalize WorkflowBuilder APIs

* "partitioner" => "assigner"
* normalize ordering so sources always to the left of targets for edges
* normalize parameter ordering so sources and targets are always first arguments
* remove `params` (users should use collection expressions instead)

* refactor: Align name with Python
2025-11-05 19:50:01 +00:00
Jacob AlberandGitHub b8a55dccb4 [BREAKING] refactor: Fix unintuitive binding of StreamAsync (#1930)
In #1551 we added a mechanism to open a Streaming workflow run without providing any input. This caused unintuitive behaviour when passing a string as input without providing a runId, resulting in the input being misinterpreted as the runId and the workflow not executing.

As well, the name caused confusion about why the Workflow was not running when using the input-less StreamAsync (since the Workflow cannot run without any messages to drive its execution).
2025-11-05 17:26:46 +00:00
Jacob AlberandGitHub b25b0af49b .NET: [BREAKING] Unify ExecutorIsh and ExecutorRegistration, unify/simplify APIs (#1637)
* refactor: Unify ExecutorIsh and ExecutorRegistration => ExecutorBinding

* Switch to more modern Record type-tree for Sum Types
* Unify APIs for getting ExecutorBinding
* Fix an issue where workflows consisting entirely of cross-run shareable executors which are not instance-resettable do not properly clear state when running non-concurrently.

* feat: Simplify function-to-executor pattern

* refactor: Normalize API naming
2025-11-03 18:20:35 +00:00
Jacob AlberandGitHub 899d8ff775 fix: .NET: Concurrency Support for Orchestrations (#1689)
Concurrent run support was recently added to workflows, but Orchestrations did not fully update to support it. A few executors were missing Cross-Run Shareable annotations, and the ConcurrentEnd executor needed to be factory-instantiated.

This also ports the fix for #1613 from #1637, to avoid waiting on that PR.
2025-10-24 23:18:51 +00:00
Jacob AlberandGitHub 3aa682082a feat: Add Cancellation API on StreamingRun (#1675) 2025-10-23 20:01:56 +00:00
Jacob AlberandGitHub b2246efa69 fix: InMemoryCheckpointManager is not JSON serializable (#1639)
Checkpointing is used by the WorkflowHostAgent to be able to support resume from a provided thread. When a CheckpointManager is not specified, we use the InMemoryCheckpointManager and serialize its state into the thread's Serialize()ed JsonElement.

At some point InMemoryCheckpointManager became not serializable, breaking this behaviour. This change restores serializability, and adds a test.
2025-10-23 19:32:52 +00:00
Jacob AlberandGitHub feb3404a27 samples: WorkflowHelper => WorkflowFactory (#1640) 2025-10-23 04:34:26 +00:00
Jacob AlberandGitHub 0ef4e739d5 refactor: [BREAKING] Remove generic Workflow<T> (#1551)
Remove input type checking in favour of explicit `.DescribeProtocolAsync()` flow. Also removes `.AsAgentAsync()` as the validation happens at workflow run time. This makes it easier to use Workflows with DI without resorting to async-over-sync.
2025-10-21 00:13:41 +00:00
Jacob AlberandGitHub 331c750515 .NET: [BREAKING] Enable sharing of workflow instances across concurrently executing runs (#1464)
* refactor: remove unused internals

* feat: Execution Mode for sharing a workflow among concurrent runs

* feat: Update WorkflowHostAgent to support concurrent execution

* Also update AsAgent APIs to support injecting a CheckpointManager and an IWorkflowExecutionEnvironment

* fix: Make Read logic consistent in DeclarativeWorkflowContext
2025-10-15 21:34:17 +00:00
Jacob AlberandGitHub 69e1ab0409 fix: Update WorkflowHostAgent post Checkpointing implementation (#1498)
WorkflowHostAgent was initially implemented before Checkpointing was available. This meant that in order to support resuming, the WorkflowHostAgent needed to keep the runs around, which broke it when stricter rules about concurrent sharing of workflows during execution were introduced.

This change updates the hosting logic to release the underlying StreamingRun when the RunStreamingAsync or RunAsync are invoked, in favour of keeping the checkpointing information in the WorkflowThread to enable resumption.
2025-10-15 18:18:28 +00:00
Jacob AlberandGitHub 4cd81fe8e7 .NET: fix: Make State Persistence APIs work better with PortableValue (#1367)
* fix: Make State Persistence APIs work better with PortableValue

* test: Temporarily disable checking for T=object in ReadStateAsync
2025-10-09 20:24:55 +00:00
Jacob AlberandGitHub 5902bcb10a .NET: [BREAKING] Propagate CancellationToken into Workflow Executors and message handlers (#1280)
* feat: Propagate CancellationToken to Executors

* Also adds cancellation propagation to `Executor`-accessible APIs
* Adds registrators for cancellable handlers to `RouteBuilder`
* [BREAKING]: Adds `CancellationToken` to `IMessageHandler.HandleAsync`

* test: Re-enable Concurrent Orchestration test

* refactor: Delete unused IInputCoordinator

* refactor: Remove superfluous argument qualifications
2025-10-08 00:28:44 +00:00
7ebe00ec3d [BREAKING] .NET: Workflow Off-Thread Execution Mode (#1233)
* Updates to async run loop.

* fix: Workflow Onwership can be release by nonowner

* fix: Incorrect handling of blockOnPending in StreamingRun

Depending on whether we are running in streaming on non-streaming mode, we may be using the StreamingRun in different ways. Unfortunately, the only place we can really know what is the actual state of execution is in the RunEventStream implementations.

This resulted in blocking where blocking was unneeded and occasionally not-blocking when blocking was needed.

The fix is to move the logic of handling this blocking into RunEventStream implementations.

* fix: Fix cleanup on error and end run

This ensures we clean up the background resources correctly.

* fix: Ensure we let the run loop proceed when shutting down

* fix: Add timeout for Input Waiting

* fix: Make the samples properly clean up `Run`s and `StreamingRun`s

* fix: Simplify Declarative Workflow Run disposal pattern

* Also fixes missing .Disposal() in Integration tests

---------

Co-authored-by: Ben Thomas <ben.thomas@microsoft.com>
2025-10-07 01:07:38 +00:00
Jacob AlberandGitHub 32e7ff00b5 .NET: Add support for Subworkflows and many threading fixes (#1066)
* feat: Add support for Workflow-as-Executor

* Fixes routing of 'object' compile-typed variables to properly take in type information
* Fixes a concurrency issue in StepTracer

* fix: Make Subworkflow ExternalRequests work properly

* fix: Threading and Concurrency fixes; prep for OffThread Mode

* refactor: Remove dead code around OffStreamRunEventStream

Currently not used, and will be replaced with a rewrite when brought back, so having it in the change is not valuable.

* ci: Work around issues with dotnet-format not properly analyzing the source

* fix: Fix the logic of AsyncCoordinator and AsyncBarrier

* Prevent individual wait cancellations from canceling the entire barrier
* Propagate information about whether the wait was completed or cancelled, and whether any waiters were present when released

* fix: Remove superfluous acces to .Keys in InProcStepTracer

* refactor: Clean up AsyncCoordinator's use of AsyncBarrier
2025-10-03 17:26:30 +00:00
Jacob AlberandGitHub cfcb90bfe0 fix: Make CheckpointInfo constructor public (#1156)
In order to be able to restore checkpoints (and even implement ICheckpointStore)
2025-10-03 15:42:04 +00:00
Jacob AlberandGitHub 9614eea875 feat: Solidify Concurrency Model for Inproc Workflows (#925)
* Disallow execution of multiple workflows at once
* Define notion of executor Reset() to allow reuse of workflows with shared executor instances
* Switch to delivering all messages to a single executor sequentially, with executors running in parallel
2025-09-26 15:44:02 +00:00
Jacob AlberandGitHub 39e071c430 .NET: Update Workflow Input/Output Redesign (#881)
* feat: Make Executor id field mandatory

When checkpointing is involved, it is critical to keep executor ids consistent between runs, even when recreating a new object tree for the workflow.

The default id-setting mechanism generated a guid for part of the id, making it not work when restoring from a checkpoint.

This change prevents this situation from arising.

* feat: Enable running untyped Workflows

With the change to enable delay-instantiation of executors and support for async Executor factory methods, we must instantiate the starting executor to know what are the valid input types for the workflow.

To avoid forcing instantiation every time, and to better support workflows with multiple input types, we enable support for build and interacting with the base Workflow type without type annotations, and remove the requirement to know a valid input type when initiating a run.

* feat: Support Output from any executor and multiple outputs.
2025-09-25 02:03:22 +00:00
2015f0dc09 .NET: [BREAKING] Support Checkpoint Serialization (#735)
* feat: Support Checkpoint Serialization

* Implements serialization roundtripping for checkpoints.
* Adds support for JSON serialization
* Adds FileSystem-based checkpoint persistence

* fix: Executor State does not deserialize correctly

The StateManager was not properly handling delay-deserialized values.

* Fix PortableValue handling in StateManager (this makes it delegate to PortableValue the uwnrapping)
* Fix UnitTest to actually test checkpoint serialization
* Additional review comment fixes

---------

Co-authored-by: Chris <66376200+crickman@users.noreply.github.com>
2025-09-17 19:57:19 +00:00
Jacob AlberandGitHub 3b81164a6d .NET: fix: MessageMerger crashes when there are no dangling messages (#660)
* fix: MessageMerger crashes when there are no dangling messages

* refactor: Better logic for AgentId in Workflow-as-Agent

If the parent "agent" instance received an Id or Name when being instantiated, we should avoid stomping over it with the subagents' ids. But if there is no parent identifier, and only a single subagent yielded identified messages, pull that in.
2025-09-10 06:10:30 +00:00
Jacob AlberandGitHub e8f1f4e785 fix: Fix Checkpoint Restore when Rehydrating Run (#642)
When checkpointing we did not persist the set of instantiated executors. This means, in turn, when we restore from a checkpoint when using Resume(Stream) rather than restoring a checkpoint in the context of an already existing (Streaming)Run, the executors never got reinstantiated and there were no executors to notify that a state should be loaded.

The fix is to ensure we persist the list and reinstantiate the executors on rehydration.

* Also adds a rehydration restore test
2025-09-08 19:22:41 +00:00
Jacob AlberandGitHub 0cae1e0adf .NET: Improve DevEx for simple Executors (#626)
* feat: Improve DevEx for simple Executors

* Add abstract types for executors that will only handle one type of message
* Add FunctionExecutor and configuration capability on delegates
* Add support for late-instantiated Executors

* refactor: Remove open-typed extension method

* refactor: Switch to TaskFactory pattern for async--from-sync

* docs: Update XML docs for publics and fix formatting

* refactor: Better naming for ExecutorIsh configuration methods

* docs: Fix typo in ExecutorIshConfigurationExtensions.ConfigureFactory
2025-09-08 19:11:53 +00:00
Jacob AlberandGitHub e1147273da .NET: fix: FanIn Edge does not work (#541)
* fix: FanIn Edge does not work

We were not creating the state for FanIn edge in EdgeMap correctly, leading to crashes. After fixing that, it turns out the logic in FanInEdgeRunner was only forwarding the last message, not all of them.

* fix: Remove duplicate code and fix typo
2025-08-28 22:25:57 +00:00
Jacob AlberandGitHub ea7cff16ce fix: ChatMessage Aggregation in AIAgentHostExecutor (#530)
The previous fix for the aggregation in AIAgentHostExecutor has a bug wherein we only include the first update from a ChatMessage in the outgoing "collected" message.

The fix is to ensure we put the collected updates into the message before sending it out.
2025-08-28 18:23:19 +00:00
Jacob AlberandGitHub 738866f4fe Aggregate ChatMessages from AgentRunUpdates before forwarding (#515)
The current implementation of AIAgentHostExecutor unwraps every incoming AgentRunResponseUpdate into a separate ChatMessage, amplifying the number of ChatMessages are actually generated, and yielding multiple messages with the same MessageId.

The fix is to aggregate by MesageId, with the expectation that agents do not interleave messages with differing ids, thus every new MessageId indicates a new ChatMessage and never an old one.
2025-08-27 22:32:27 +00:00
Jacob AlberandGitHub 80e89a7d87 .NET: Implement browse/clear functionality for state (#513)
* feat: Implement browse/clear functionality for state

* fix: Assertion comments in StateManagerTests
2025-08-27 21:12:21 +00:00
78125f019a .NET: Make WorkflowBuilder more intuititve (#503)
* feat: Make WorkflowBuilder more intutitve

Right now Executorish binding has some unintutitive behaviour. When a user adds an eecutor with an id of an executor that already exists, we silently replace it, if the user provides it inside of add_edge. When a user introduces an executor via an unbound id, the user must bind it via BindExecutor, even though the registration is created implicitly when an edge id added.

The change will remove the invisible update in favor of a "best efforts" check of type and instance equality.

* Expand errors when rebinding to disallowed

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-26 22:42:07 +00:00
Jacob AlberandGitHub 8544cd9b03 fix: State Updates are not published without CheckpointManager (#501) 2025-08-26 17:41:48 +00:00
Jacob AlberandGitHub d7c39d72cc .NET: feat: Implement Checkpointing API (#420)
* feat: Implement Checkpointing API

* refactor: Normalzie Namespaces and break out multi-class files

* feat: Support checkpointing in AIAgentHostExecutor

* test: Representation tests

* feat: Add Step-level Tracing and WorkflowEvents

* feat: Add Checkpointing Sample and Smoke Test

* Fixes an issue where StateManager was not properly clearing the incoming queued updates.
* Fixes order of checkpointing and in-step event publication
* Adds import of RunContext state on LoadCheckpoint
* Add re-firing of events for unserviced ExternalRequests on Checkpoint load

* docs: Add documentation to publics

* Also adds documentation to ICheckpointManager which may go public

* refactor: Fix Union Aggregators and add Tests

* fix: Fix issues raised in PR comments and remove dead code
2025-08-25 23:04:38 +00:00
Jacob AlberandGitHub b26d9c95fe feat: Expose wrapped Request/Response API (#471)
* Allows creation of ExternalRequest objects directly to control the requestId
* Allows receiving ExternalResponse objects rather than unwrapped Data
* Normalizing naming
2025-08-22 22:07:28 +00:00
Jacob AlberandGitHub 88c51013c6 .NET: feat: Host Workflow as AIAgent (#469)
* feat: Host Workflow as AIAgent

* Also changes AIAgent-as-Executor to use streaming runs and streaming
  events
* Also enables default setting for yielding events

* fix: Infinite loop in GenerateNewId()

* docs: Spelling

* test: Add Workflow-as-Agent sample and test
2025-08-22 22:01:30 +00:00
Jacob AlberandGitHub baaa9c0aee .NET: feat: Improve Support for AIAgent-as-Executor (#432)
* feat: Support Executor-targeted messages

This adds support for only sending a message to a given executor. Messages will still only route through connected edges.

* feat: Support sending all valid input types after starting a run

* feat: Normalize AIAgent-as-Executor Message Protocol to use MEAI types
2025-08-19 20:04:03 +00:00
32711cfa95 .Net: WIP: feat: Define Workflow and Executor APIs (#261)
* feat: Define Workflow and Executor APIs

* feat: Define IExecutionContext and Events

* feat: Simple Workflow Demos

* refactor: Move Workflows classes to separate assembly

* feat: Move FanOut/In to LowLevel API with new semantics

* feat: Implement Local Execution

* refactor: Assembly name .Workflow => .Workflows

* feat: Enable Default Message Handling

* also lifts Bind in MessageHandlerInfo to better be able to direclty invoke handlers (for AOT, later)

* feat: Implement StreamingHandle APIs

This allows the user to respond to WorkflowEvents with external messages, enabling HIL.

* feat: Add checks for duplicate edges and chain cycles

* feat: Add built-in WorkflowEvents

* refactor: Pull classes into own files

* refactor: Simplify Disposal pattern in Executor

* refactor: Break EdgeRunner file into per-type files

* refactor: Use Throw.IfNull()

* refactor: Remove AddLoop()

Per https://github.com/microsoft/agent-framework/pull/272#discussion_r2241739079 we decided this was not very useful.

* refactor: Normalize use of ValueTask

* fix: Build Break from removing .AddLoop

* refactor: Explicit routing and RouteBuilder

Split out reflection from MessageRouter implemention into build phase, enabling AOT compilation to drive RouteBuilding without reflection.

* test: Add Reflection/Invocation tests

* fix: Terminate on Completion event

* refactor: Update public API surface

* feat: Add support for external requests

* feat: Support hosting AIAgent instances in Workflows

* fix: Fix routing to go through Executor.ExecuteAsync

* test: Update samples for "must SendMessage" semantics

* Add invoking samples to unit tests to avoid future breaks

* fix: ExternalRequest should block Workflow completion

* feat: Normalize API surface against Python

* Also adds xmldoc to all public APIs

* refactor: Normalize UnitTest and Sample namespaces

* fix: Formatting

* refactor: Normalize project/folder names

* feat: Remove DynamicCodeExecution from ValueTaskTypeErasure

* fix: Fix ILTrim warnings

* docs: Add missing docs and fix typos

* feat: Hosted Agents should report Run events

* fix: Fix type propagation for ILTrim changes

* refactor: Simplify DynamicallyAccessedMembers annotations

* sample: Use static-Type construction of InputPort

* feat: Support non-Streaming Run Mode

* test: Add test for non-streaming execution

* refactor: Remove unused types

* refactor: Simplify Event and EdgeData type hierarchies

* feat: Add Switch (=Conditional Edge Group) control flow

* feat: Make .NET AutoSend the MessageHandler result

* feat: Implement State APIs

* refactor: Simplify public namespaces and code organization

* refactor: Reconcile .NET and Python names

---------

Co-authored-by: Chris <66376200+crickman@users.noreply.github.com>
2025-08-13 22:34:39 +00:00